diff --git a/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeType.java b/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeType.java index 3443b490..2c4223b8 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeType.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeType.java @@ -8,7 +8,6 @@ import java.util.HashSet; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.function.Supplier; import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; @@ -20,9 +19,9 @@ public interface TreeType { TreeType NONE = new TreeTypeImpl( Unicopia.id("none"), false, - new Weighted>(), Set.of(), - Set.of() + Set.of(), + Weighted.of() ); Direction[] WIDE_DIRS = new Direction[] { Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST }; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeTypeImpl.java b/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeTypeImpl.java index 4ebd4b08..6a8567c8 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeTypeImpl.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeTypeImpl.java @@ -1,7 +1,6 @@ package com.minelittlepony.unicopia.ability.data.tree; -import com.minelittlepony.unicopia.util.Weighted; - +import java.util.Optional; import java.util.Set; import java.util.function.Supplier; @@ -11,21 +10,13 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; -public final class TreeTypeImpl implements TreeType { - private final Identifier name; - private final boolean wideTrunk; - private final Set logs; - private final Set leaves; - private final Weighted> pool; - - TreeTypeImpl(Identifier name, boolean wideTrunk, Weighted> pool, Set logs, Set leaves) { - this.name = name; - this.wideTrunk = wideTrunk; - this.pool = pool; - this.logs = logs; - this.leaves = leaves; - } - +public record TreeTypeImpl ( + Identifier name, + boolean wideTrunk, + Set logs, + Set leaves, + Supplier>> pool +) implements TreeType { @Override public boolean isLeaves(BlockState state) { return findMatch(leaves, state) && isNonPersistent(state); @@ -46,20 +37,10 @@ public final class TreeTypeImpl implements TreeType { return pool.get().map(Supplier::get).orElse(ItemStack.EMPTY); } - @Override - public boolean equals(Object o) { - return o instanceof TreeTypeImpl && name.compareTo(((TreeTypeImpl)o).name) == 0; - } - private static boolean findMatch(Set ids, BlockState state) { return ids.contains(Registry.BLOCK.getId(state.getBlock())); } - @Override - public int hashCode() { - return name.hashCode(); - } - static boolean isNonPersistent(BlockState state) { return !state.contains(LeavesBlock.PERSISTENT) || !state.get(LeavesBlock.PERSISTENT); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeTypeLoader.java b/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeTypeLoader.java index 98887231..5935b21e 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeTypeLoader.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/data/tree/TreeTypeLoader.java @@ -65,18 +65,13 @@ public class TreeTypeLoader extends JsonDataLoader implements IdentifiableResour wideTrunk = buffer.readBoolean(); } - private Weighted> getWeighted(Weighted> weighted) { - drops.forEach(drop -> drop.appendDrop(weighted)); - return weighted; - } - public TreeType toTreeType(Identifier id) { return new TreeTypeImpl( id, wideTrunk, - getWeighted(new Weighted>()), Objects.requireNonNull(logs, "TreeType must have logs"), - Objects.requireNonNull(leaves, "TreeType must have leaves") + Objects.requireNonNull(leaves, "TreeType must have leaves"), + Weighted.of(weighted -> drops.forEach(drop -> drop.appendDrop(weighted))) ); } @@ -96,7 +91,7 @@ public class TreeTypeLoader extends JsonDataLoader implements IdentifiableResour item = buffer.readIdentifier(); } - void appendDrop(Weighted> weighted) { + void appendDrop(Weighted.Builder> weighted) { Registry.ITEM.getOrEmpty(item).ifPresent(item -> { weighted.put(weight, item::getDefaultStack); }); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java index 9ce0a4cb..9036ac0a 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/NecromancySpell.java @@ -1,7 +1,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.function.Supplier; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.AbstractAreaEffectSpell; @@ -32,12 +32,13 @@ import net.minecraft.world.WorldEvents; * An area-effect spell that summons the undead. */ public class NecromancySpell extends AbstractAreaEffectSpell { - private final Weighted> spawnPool = new Weighted>() + private final Supplier>> spawnPool = new Weighted.Builder>() .put(7, EntityType.ZOMBIE) .put(4, EntityType.HUSK) .put(3, EntityType.DROWNED) .put(2, EntityType.ZOMBIFIED_PIGLIN) - .put(1, EntityType.ZOMBIE_VILLAGER); + .put(1, EntityType.ZOMBIE_VILLAGER) + .build(); private final List> summonedEntities = new ArrayList<>(); diff --git a/src/main/java/com/minelittlepony/unicopia/util/Weighted.java b/src/main/java/com/minelittlepony/unicopia/util/Weighted.java index 0ca6718f..398c06a2 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/Weighted.java +++ b/src/main/java/com/minelittlepony/unicopia/util/Weighted.java @@ -1,80 +1,86 @@ package com.minelittlepony.unicopia.util; -import java.util.List; -import java.util.Optional; -import java.util.Random; +import java.util.*; import java.util.function.Consumer; +import java.util.function.Supplier; import org.jetbrains.annotations.NotNull; -import com.google.common.collect.Lists; +import net.minecraft.util.Pair; -public class Weighted { +public final class Weighted { + private static final Supplier> EMPTY = Optional::empty; - private static final Random rand = new Random(); - - private float totalWeight = 0; - - private final List entries = Lists.newArrayList(); - - public static Weighted of(Consumer> constructor) { - Weighted result = new Weighted<>(); + @SuppressWarnings("unchecked") + public static Supplier> of() { + return (Supplier>)(Object)EMPTY; + } + public static Supplier> of(Consumer> constructor) { + Weighted.Builder result = new Weighted.Builder<>(); constructor.accept(result); - - return result; + return result.build(); } - public Weighted put(int weight, @NotNull T value) { - entries.add(new Entry(weight, value)); + public final static class Builder { + private static final Random RANDOM = new Random(); - totalWeight += weight; + private float totalWeight = 0; - recalculate(); + private final List, Range>> entries = new ArrayList<>(); - return this; - } - - private void recalculate() { - float rangeStart = 0; - - for (Entry i : entries) { - i.min = rangeStart; - i.max = rangeStart + (i.weight/totalWeight); - - rangeStart = i.max; - } - } - - public Optional get() { - if (entries.isEmpty()) { - return Optional.empty(); + public Builder putAll(Map map) { + map.forEach(this::put); + return this; } - float random = rand.nextFloat(); + public Builder put(int weight, @NotNull T value) { + entries.add(new Pair<>(new WeightedValue<>(weight, value), new Range())); - return entries.stream() - .filter(i -> random >= i.min && random <= i.max) - .map(Entry::getResult) - .findFirst(); - } + totalWeight += weight; - class Entry { + float rangeStart = 0; - final float weight; + for (var i : entries) { + rangeStart = i.getRight().set(rangeStart, (i.getLeft().weight() / totalWeight)); + } - final T result; - - float min; - float max; - - Entry(int weight, T result) { - this.weight = weight; - this.result = result; + return this; } - T getResult() { - return result; + public Supplier> build() { + if (entries.isEmpty()) { + return of(); + } + if (entries.size() == 1) { + final var val = Optional.ofNullable(entries.get(0).getLeft().result()); + return () -> val; + } + final var entries = new ArrayList<>(this.entries); + return () -> { + final float pointer = RANDOM.nextFloat(); + return entries.stream() + .filter(i -> i.getRight().isIn(pointer)) + .map(i -> i.getLeft().result()) + .findFirst(); + }; + } + + private record WeightedValue (float weight, T result) {} + + private final class Range { + float min; + float max; + + public boolean isIn(float pointer) { + return pointer >= min && pointer <= max; + } + + public float set(float start, float size) { + min = start; + max = start + size; + return max; + } } } }