From 0dc386096636bd71da6866fa3103b94f04d16ccb Mon Sep 17 00:00:00 2001 From: Sollace Date: Sat, 13 Feb 2021 13:50:24 +0200 Subject: [PATCH] Rewrite and improve tree traversal --- .../unicopia/TreeTraverser.java | 182 ---------------- .../com/minelittlepony/unicopia/TreeType.java | 200 +++++++++++++----- .../unicopia/TreeTypeLoader.java | 95 +++++++++ .../com/minelittlepony/unicopia/Unicopia.java | 4 + .../ability/EarthPonyKickAbility.java | 80 ++++--- .../unicopia/util/PosHelper.java | 3 + .../data/unicopia/tree_types/acacia.json | 9 + .../data/unicopia/tree_types/birch.json | 9 + .../data/unicopia/tree_types/dark_oak.json | 10 + .../data/unicopia/tree_types/jungle.json | 10 + .../data/unicopia/tree_types/oak.json | 9 + .../data/unicopia/tree_types/spruce.json | 10 + 12 files changed, 344 insertions(+), 277 deletions(-) delete mode 100644 src/main/java/com/minelittlepony/unicopia/TreeTraverser.java create mode 100644 src/main/java/com/minelittlepony/unicopia/TreeTypeLoader.java create mode 100644 src/main/resources/data/unicopia/tree_types/acacia.json create mode 100644 src/main/resources/data/unicopia/tree_types/birch.json create mode 100644 src/main/resources/data/unicopia/tree_types/dark_oak.json create mode 100644 src/main/resources/data/unicopia/tree_types/jungle.json create mode 100644 src/main/resources/data/unicopia/tree_types/oak.json create mode 100644 src/main/resources/data/unicopia/tree_types/spruce.json diff --git a/src/main/java/com/minelittlepony/unicopia/TreeTraverser.java b/src/main/java/com/minelittlepony/unicopia/TreeTraverser.java deleted file mode 100644 index ef7ebb6a..00000000 --- a/src/main/java/com/minelittlepony/unicopia/TreeTraverser.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.minelittlepony.unicopia; - -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; - -import com.minelittlepony.unicopia.util.PosHelper; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.LeavesBlock; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.World; - -public class TreeTraverser { - - public static class Remover { - /** - * Removes the tree located at the given position. - */ - public static void removeTree(World w, BlockPos pos) { - BlockState log = w.getBlockState(pos); - - if (Measurer.measureTree(w, log, pos) > 0) { - removeTreePart(w, log, Ascender.ascendTrunk(new HashSet(), w, pos, log, 0).get(), 0); - } - } - - private static void removeTreePart(World w, BlockState log, BlockPos pos, int level) { - if (level < 10 && isWoodOrLeaf(w, log, pos)) { - breakBlock(w, pos, level < 5); - - PosHelper.all(pos, p -> { - removeTreePart(w, log, p, level + 1); - }, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST); - } - } - } - - public static class Ascender { - /** - * Locates the top of the tree's trunk. Usually the point where wood meets leaves. - */ - public static BlockPos ascendTree(World w, BlockState log, BlockPos pos, boolean remove) { - int breaks = 0; - while (variantAndBlockEquals(w.getBlockState(pos.up()), log)) { - if (PosHelper.any(pos, p -> isLeaves(w.getBlockState(p), log), Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST)) { - break; - } - - if (remove) { - breakBlock(w, pos, breaks++ < 10); - } - pos = pos.up(); - } - return pos; - } - - static Optional ascendTrunk(Set done, World w, BlockPos pos, BlockState log, int level) { - if (level < 3 && !done.contains(pos)) { - done.add(pos); - - BlockPos.Mutable result = new BlockPos.Mutable(); - result.set(ascendTree(w, log, pos, true)); - - PosHelper.all(pos, p -> { - if (variantAndBlockEquals(w.getBlockState(pos.east()), log)) { - ascendTrunk(done, w, pos.east(), log, level + 1).filter(a -> a.getY() > result.getY()).ifPresent(result::set); - } - }, Direction.EAST, Direction.WEST, Direction.NORTH, Direction.SOUTH); - - done.add(result.toImmutable()); - return Optional.of(result.toImmutable()); - } - return Optional.of(pos); - } - } - - public static class Descender { - /** - * Recursively locates the base of the tree. - */ - public static Optional descendTree(World w, BlockState log, BlockPos pos) { - return descendTreePart(new HashSet(), w, log, new BlockPos.Mutable(pos.getX(), pos.getY(), pos.getZ())); - } - - private static Optional descendTreePart(Set done, World w, BlockState log, BlockPos.Mutable pos) { - if (done.contains(pos) || !variantAndBlockEquals(w.getBlockState(pos), log)) { - return Optional.empty(); - } - - done.add(pos.toImmutable()); - while (variantAndBlockEquals(w.getBlockState(pos.down()), log)) { - done.add(pos.move(Direction.DOWN).toImmutable()); - } - - PosHelper.all(pos.toImmutable(), p -> { - descendTreePart(done, w, log, new BlockPos.Mutable(p.getX(), p.getY(), p.getZ())).filter(a -> a.getY() < pos.getY()).ifPresent(pos::set); - }, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST); - - done.add(pos.toImmutable()); - return Optional.of(pos.toImmutable()); - } - } - - public static class Measurer { - /** - * Counts the number of logs and leaves present in the targeted tree. - */ - public static int measureTree(World w, BlockState log, BlockPos pos) { - Set logs = new HashSet<>(); - Set leaves = new HashSet<>(); - - countParts(logs, leaves, w, log, pos); - - return logs.size() <= (leaves.size() / 2) ? logs.size() + leaves.size() : 0; - } - - /** - * Counts the number of logs and leaves present in the targeted tree. - */ - public static Set getParts(World w, BlockState log, BlockPos pos) { - Set parts = new HashSet<>(); - - countParts(parts, parts, w, log, pos); - - return parts; - } - - - private static void countParts(Set logs, Set leaves, World w, BlockState log, BlockPos pos) { - if (logs.contains(pos) || leaves.contains(pos)) { - return; - } - - BlockState state = w.getBlockState(pos); - boolean yay = false; - - if (isLeaves(state, log) && !state.get(LeavesBlock.PERSISTENT)) { - leaves.add(pos); - yay = true; - } else if (variantAndBlockEquals(state, log)) { - logs.add(pos); - yay = true; - } - - if (yay) { - PosHelper.all(pos, p -> { - countParts(logs, leaves, w, log, p); - }, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST); - } - } - } - - private static void breakBlock(World w, BlockPos pos, boolean destroy) { - if (destroy) { - w.breakBlock(pos, true); - } else { - Block.dropStacks(w.getBlockState(pos), w, pos); - w.setBlockState(pos, Blocks.AIR.getDefaultState(), 3); - } - } - - public static boolean isWoodOrLeaf(World w, BlockState log, BlockPos pos) { - BlockState state = w.getBlockState(pos); - return variantAndBlockEquals(state, log) || (isLeaves(state, log) && !state.get(LeavesBlock.PERSISTENT)); - } - - private static boolean isLeaves(BlockState state, BlockState log) { - return state.getBlock() instanceof LeavesBlock && variantEquals(state, log); - } - - private static boolean variantAndBlockEquals(BlockState one, BlockState two) { - return (one.getBlock() == two.getBlock()) && variantEquals(one, two); - } - - private static boolean variantEquals(BlockState one, BlockState two) { - return TreeType.get(one).equals(TreeType.get(two)); - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/TreeType.java b/src/main/java/com/minelittlepony/unicopia/TreeType.java index ce3a22ba..e2590413 100644 --- a/src/main/java/com/minelittlepony/unicopia/TreeType.java +++ b/src/main/java/com/minelittlepony/unicopia/TreeType.java @@ -1,75 +1,165 @@ package com.minelittlepony.unicopia; -import java.util.stream.Collectors; - -import com.minelittlepony.unicopia.item.UItems; +import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.Weighted; -import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import java.util.function.Supplier; -import net.minecraft.block.Block; import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; +import net.minecraft.block.LeavesBlock; import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; public final class TreeType { - // TODO: move to datapack - private static final Set REGISTRY = new HashSet<>(); + public static final TreeType NONE = new TreeType( + new Identifier("unicopia", "none"), + false, + new Weighted>(), + Collections.emptySet(), + Collections.emptySet() + ); + private static final Direction[] WIDE_DIRS = new Direction[] { Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST }; - private static final Supplier ROTTEN = () -> new ItemStack(UItems.ROTTEN_APPLE); - private static final Supplier SWEET = () -> new ItemStack(UItems.SWEET_APPLE); - private static final Supplier GREEN = () -> new ItemStack(UItems.GREEN_APPLE); - private static final Supplier ZAP = () -> new ItemStack(UItems.ZAP_APPLE); - private static final Supplier SOUR = () -> new ItemStack(UItems.SOUR_APPLE); - private static final Supplier RED = () -> new ItemStack(Items.APPLE); - - public static final TreeType NONE = new TreeType("none", new Weighted>()); - public static final TreeType OAK = new TreeType("oak", new Weighted>() - .put(1, ROTTEN) - .put(2, GREEN) - .put(3, RED), Blocks.OAK_LOG, Blocks.OAK_LEAVES); - public static final TreeType BIRCH = new TreeType("birch", new Weighted>() - .put(1, ROTTEN) - .put(2, SWEET) - .put(5, GREEN), Blocks.BIRCH_LOG, Blocks.BIRCH_LEAVES); - public static final TreeType SPRUCE = new TreeType("spruce", new Weighted>() - .put(1, SOUR) - .put(2, GREEN) - .put(3, SWEET) - .put(4, ROTTEN), Blocks.SPRUCE_LOG, Blocks.SPRUCE_LEAVES); - public static final TreeType ACACIA = new TreeType("acacia", new Weighted>() - .put(1, ROTTEN) - .put(2, SWEET) - .put(5, GREEN), Blocks.ACACIA_LOG, Blocks.ACACIA_LEAVES); - public static final TreeType JUNGLE = new TreeType("jungle", new Weighted>() - .put(5, GREEN) - .put(2, SWEET) - .put(1, ZAP), Blocks.JUNGLE_LOG, Blocks.JUNGLE_LEAVES); - public static final TreeType DARK_OAK = new TreeType("dark_oak", new Weighted>() - .put(1, ROTTEN) - .put(2, SWEET) - .put(5, ZAP), Blocks.DARK_OAK_LOG, Blocks.DARK_OAK_LEAVES); - - private final String name; - private final Set blocks; + private final Identifier name; + private final boolean wideTrunk; + private final Set logs; + private final Set leaves; private final Weighted> pool; - private TreeType(String name, Weighted> pool, Block...blocks) { + TreeType(Identifier name, boolean wideTrunk, Weighted> pool, Set logs, Set leaves) { this.name = name; + this.wideTrunk = wideTrunk; this.pool = pool; - this.blocks = Arrays.stream(blocks).map(Registry.BLOCK::getId) - .collect(Collectors.toSet()); - REGISTRY.add(this); + this.logs = logs; + this.leaves = leaves; + } + + public void traverse(World w, BlockPos start, Reactor consumer) { + traverse(w, start, consumer, consumer); + } + + public void traverse(World w, BlockPos start, Reactor logConsumer, Reactor leavesConsumer) { + traverse(new HashSet<>(), new HashSet<>(), w, start, 0, 50, logConsumer, leavesConsumer); + } + + public void traverse(Set logs, Set leaves, World w, BlockPos start, int recurseLevel, int maxRecurse, Reactor logConsumer, Reactor leavesConsumer) { + if (this == NONE) { + return; + } + + traverseInner(logs, leaves, w, findBase(w, start), recurseLevel, maxRecurse, logConsumer, leavesConsumer); + } + + private void traverseInner(Set logs, Set leaves, World w, BlockPos pos, int recurseLevel, int maxRecurse, Reactor logConsumer, Reactor leavesConsumer) { + + if (this == NONE || (maxRecurse > 0 && recurseLevel >= maxRecurse) || logs.contains(pos) || leaves.contains(pos)) { + return; + } + + BlockState state = w.getBlockState(pos); + boolean yay = false; + + if (isLeaves(state)) { + leaves.add(pos); + yay = true; + if (leavesConsumer != null) { + leavesConsumer.react(w, state, pos, recurseLevel); + } + } else if (isLog(state)) { + logs.add(pos); + yay = true; + if (logConsumer != null) { + logConsumer.react(w, state, pos, recurseLevel); + } + } + + if (yay) { + PosHelper.all(pos, p -> traverseInner(logs, leaves, w, p, recurseLevel + 1, maxRecurse, logConsumer, leavesConsumer), WIDE_DIRS); + } + } + + /** + * Recursively locates the base of the tree. + */ + public BlockPos findBase(World w, BlockPos pos) { + return findBase(new HashSet(), w, new BlockPos.Mutable(pos.getX(), pos.getY(), pos.getZ())).get(); + } + + private Optional findBase(Set done, World w, BlockPos.Mutable pos) { + if (done.contains(pos) || !isLog(w.getBlockState(pos))) { + return Optional.empty(); + } + + done.add(pos.toImmutable()); + while (isLog(w.getBlockState(pos.down()))) { + done.add(pos.move(Direction.DOWN).toImmutable()); + } + + if (wideTrunk) { + PosHelper.all(pos.toImmutable(), p -> findBase(done, w, new BlockPos.Mutable(p.getX(), p.getY(), p.getZ())) + .filter(a -> a.getY() < pos.getY()) + .ifPresent(pos::set), PosHelper.HORIZONTAL); + } + + done.add(pos.toImmutable()); + return Optional.of(pos.toImmutable()); + } + + /** + * Counts the number of logs and leaves present in the targeted tree. + */ + public int countBlocks(World w, BlockPos pos) { + if (this == NONE) { + return 0; + } + + Set logs = new HashSet<>(); + Set leaves = new HashSet<>(); + + traverseInner(logs, leaves, w, findBase(w, pos), 0, 50, null, null); + + int logCount = logs.size(); + + logs.clear(); + leaves.clear(); + + traverseInner(logs, leaves, w, findCanopy(w, pos), 0, 50, null, null); + + return logCount <= (leaves.size() / 2) ? logCount + leaves.size() : 0; + } + + /** + * Locates the top of the tree's trunk. Usually the point where wood meets leaves. + */ + public BlockPos findCanopy(World w, BlockPos pos) { + while (isLog(w.getBlockState(pos.up()))) { + if (PosHelper.any(pos, p -> isLeaves(w.getBlockState(p)), PosHelper.HORIZONTAL)) { + break; + } + + pos = pos.up(); + } + return pos; + } + + public boolean isLeaves(BlockState state) { + return findMatch(leaves, state) && (!state.contains(LeavesBlock.PERSISTENT) || !state.get(LeavesBlock.PERSISTENT)); + } + + public boolean isLog(BlockState state) { + return findMatch(logs, state); } public boolean matches(BlockState state) { - return blocks.contains(Registry.BLOCK.getId(state.getBlock())); + return isLeaves(state) || isLog(state); } public ItemStack pickRandomStack() { @@ -77,7 +167,7 @@ public final class TreeType { } public static TreeType get(BlockState state) { - return REGISTRY.stream().filter(type -> type.matches(state)).findFirst().orElse(TreeType.NONE); + return TreeTypeLoader.INSTANCE.get(state); } @Override @@ -85,8 +175,16 @@ public final class TreeType { return o instanceof TreeType && name.compareTo(((TreeType)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(); } + + public interface Reactor { + void react(World w, BlockState state, BlockPos pos, int recurseLevel); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/TreeTypeLoader.java b/src/main/java/com/minelittlepony/unicopia/TreeTypeLoader.java new file mode 100644 index 00000000..4f1b02ee --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/TreeTypeLoader.java @@ -0,0 +1,95 @@ +package com.minelittlepony.unicopia; + +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Supplier; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.minelittlepony.common.util.settings.ToStringAdapter; +import com.minelittlepony.unicopia.util.Weighted; + +import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; +import net.minecraft.block.BlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.resource.JsonDataLoader; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; +import net.minecraft.util.registry.Registry; + +public class TreeTypeLoader extends JsonDataLoader implements IdentifiableResourceReloadListener { + + private static final Identifier ID = new Identifier("unicopia", "data/tree_type"); + + private static final Gson GSON = new GsonBuilder() + .registerTypeAdapter(Identifier.class, new ToStringAdapter<>(Identifier::new)) + .create(); + + static final TreeTypeLoader INSTANCE = new TreeTypeLoader(); + + private final Set entries = new HashSet<>(); + + TreeTypeLoader() { + super(GSON, "tree_types"); + } + + @Override + public Identifier getFabricId() { + return ID; + } + + public TreeType get(BlockState state) { + return entries.stream().filter(type -> type.matches(state)).findFirst().orElse(TreeType.NONE); + } + + @Override + protected void apply(Map resources, ResourceManager manager, Profiler profiler) { + entries.clear(); + + for (Map.Entry entry : resources.entrySet()) { + try { + TreeTypeDef typeDef = GSON.fromJson(entry.getValue(), TreeTypeDef.class); + + if (typeDef != null) { + entries.add(new TreeType( + entry.getKey(), + typeDef.wideTrunk, + typeDef.getWeighted(new Weighted>()), + Objects.requireNonNull(typeDef.logs, "TreeType must have logs"), + Objects.requireNonNull(typeDef.leaves, "TreeType must have leaves") + )); + } + } catch (IllegalArgumentException | JsonParseException e) { + + } + } + } + + static class TreeTypeDef { + Set logs; + Set leaves; + Set drops; + boolean wideTrunk; + + Weighted> getWeighted(Weighted> weighted) { + drops.forEach(drop -> drop.appendDrop(weighted)); + return weighted; + } + + static class Drop { + int weight; + Identifier item; + + void appendDrop(Weighted> weighted) { + Registry.ITEM.getOrEmpty(item).ifPresent(item -> { + weighted.put(weight, item::getDefaultStack); + }); + } + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/Unicopia.java b/src/main/java/com/minelittlepony/unicopia/Unicopia.java index 9de5a878..0e816c25 100644 --- a/src/main/java/com/minelittlepony/unicopia/Unicopia.java +++ b/src/main/java/com/minelittlepony/unicopia/Unicopia.java @@ -2,6 +2,9 @@ package com.minelittlepony.unicopia; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.minecraft.resource.ResourceType; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -37,6 +40,7 @@ public class Unicopia implements ModInitializer { AwaitTickQueue.tick(w); ((BlockDestructionManager.Source)w).getDestructionManager().tick(); }); + ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(TreeTypeLoader.INSTANCE); UItems.bootstrap(); UPotions.bootstrap(); diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java index 29b35b1b..c8f99949 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyKickAbility.java @@ -1,6 +1,5 @@ package com.minelittlepony.unicopia.ability; -import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -9,29 +8,23 @@ import javax.annotation.Nullable; import com.google.common.collect.Lists; import com.minelittlepony.unicopia.BlockDestructionManager; import com.minelittlepony.unicopia.Race; -import com.minelittlepony.unicopia.TreeTraverser; import com.minelittlepony.unicopia.TreeType; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Pos; import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.RayTraceHelper; import com.minelittlepony.unicopia.util.WorldEvent; import com.minelittlepony.unicopia.util.shape.Shape; import com.minelittlepony.unicopia.util.shape.Sphere; -import net.minecraft.block.BlockState; +import net.minecraft.block.Block; import net.minecraft.block.Blocks; -import net.minecraft.block.LeavesBlock; import net.minecraft.entity.ItemEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.particle.BlockStateParticleEffect; import net.minecraft.particle.ParticleTypes; -import net.minecraft.tag.BlockTags; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; /** * Earth Pony kicking ability @@ -65,11 +58,11 @@ public class EarthPonyKickAbility implements Ability { if (p.isPresent()) { BlockPos pos = p.get(); - BlockState state = player.getWorld().getBlockState(pos); + TreeType tree = TreeType.get(player.getWorld().getBlockState(pos)); - if (state.getBlock().isIn(BlockTags.LOGS)) { - pos = TreeTraverser.Descender.descendTree(player.getWorld(), state, pos).get(); - if (TreeTraverser.Measurer.measureTree(player.getWorld(), state, pos) > 0) { + if (tree != TreeType.NONE) { + pos = tree.findBase(player.getWorld(), pos); + if (tree.countBlocks(player.getWorld(), pos) > 0) { return new Pos(pos); } } @@ -101,12 +94,19 @@ public class EarthPonyKickAbility implements Ability { if (destr.getBlockDestruction(pos) + 4 >= BlockDestructionManager.MAX_DAMAGE) { if (!harmed || player.world.random.nextInt(30) == 0) { - TreeTraverser.Remover.removeTree(player.world, pos); + TreeType.get(player.world.getBlockState(pos)).traverse(player.world, pos, (w, state, p, recurseLevel) -> { + if (recurseLevel < 5) { + w.breakBlock(p, true); + } else { + Block.dropStacks(w.getBlockState(p), w, p); + w.setBlockState(p, Blocks.AIR.getDefaultState(), 3); + } + }); } iplayer.subtractEnergyCost(3); } else { - int cost = dropApples(player.world, pos); + int cost = dropApples(player, pos); if (cost > 0) { iplayer.subtractEnergyCost(cost * 3); @@ -149,23 +149,32 @@ public class EarthPonyKickAbility implements Ability { } } - private int dropApples(World w, BlockPos pos) { - BlockState log = w.getBlockState(pos); - int size = TreeTraverser.Measurer.measureTree(w, log, pos); + private int dropApples(PlayerEntity player, BlockPos pos) { + TreeType tree = TreeType.get(player.world.getBlockState(pos)); - if (size > 0) { - BlockDestructionManager destr = ((BlockDestructionManager.Source)w).getDestructionManager(); - TreeTraverser.Measurer.getParts(w, log, pos).forEach(position -> { - destr.damageBlock(position, 4); - }); + if (tree.countBlocks(player.world, pos) > 0) { List capturedDrops = Lists.newArrayList(); - dropApplesPart(capturedDrops, new ArrayList(), w, log, pos, 0); + tree.traverse(player.world, pos, (world, state, position, recurse) -> { + affectBlockChange(player, position); + }, (world, state, position, recurse) -> { + affectBlockChange(player, position); + + if (world.getBlockState(position.down()).isAir()) { + WorldEvent.play(WorldEvent.DESTROY_BLOCK, world, position, state); + capturedDrops.add(new ItemEntity(world, + position.getX() + world.random.nextFloat(), + position.getY() - 0.5, + position.getZ() + world.random.nextFloat(), + tree.pickRandomStack() + )); + } + }); capturedDrops.forEach(item -> { item.setToDefaultPickupDelay(); - w.spawnEntity(item); + player.world.spawnEntity(item); }); return capturedDrops.size() / 3; @@ -174,27 +183,10 @@ public class EarthPonyKickAbility implements Ability { return 0; } - private static void dropApplesPart(List drops, List done, World w, BlockState log, BlockPos pos, int level) { - if (!done.contains(pos)) { - done.add(pos); - pos = TreeTraverser.Ascender.ascendTree(w, log, pos, false); - if (level < 10 && TreeTraverser.isWoodOrLeaf(w, log, pos)) { - BlockState state = w.getBlockState(pos); + private void affectBlockChange(PlayerEntity player, BlockPos position) { + BlockDestructionManager destr = ((BlockDestructionManager.Source)player.world).getDestructionManager(); - if (state.getBlock() instanceof LeavesBlock && w.getBlockState(pos.down()).isAir()) { - WorldEvent.play(WorldEvent.DESTROY_BLOCK, w, pos, state); - drops.add(new ItemEntity(w, - pos.getX() + w.random.nextFloat(), - pos.getY() - 0.5, - pos.getZ() + w.random.nextFloat(), - TreeType.get(log).pickRandomStack() - )); - } + destr.damageBlock(position, 4); - PosHelper.all(pos, p -> { - dropApplesPart(drops, done, w, log, p, level + 1); - }, Direction.UP, Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST); - } - } } } diff --git a/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java b/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java index 830fe208..95ff99b5 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java +++ b/src/main/java/com/minelittlepony/unicopia/util/PosHelper.java @@ -1,5 +1,6 @@ package com.minelittlepony.unicopia.util; +import java.util.Arrays; import java.util.Iterator; import java.util.Spliterator; import java.util.Spliterators.AbstractSpliterator; @@ -19,6 +20,8 @@ import net.minecraft.world.World; public interface PosHelper { + Direction[] HORIZONTAL = Arrays.stream(Direction.values()).filter(d -> d.getAxis().isHorizontal()).toArray(Direction[]::new); + static Vec3d offset(Vec3d a, Vec3i b) { return a.add(b.getX(), b.getY(), b.getZ()); } diff --git a/src/main/resources/data/unicopia/tree_types/acacia.json b/src/main/resources/data/unicopia/tree_types/acacia.json new file mode 100644 index 00000000..10ce0f90 --- /dev/null +++ b/src/main/resources/data/unicopia/tree_types/acacia.json @@ -0,0 +1,9 @@ +{ + "logs": [ "minecraft:acacia_log", "minecraft:acacia_wood" ], + "leaves": [ "minecraft:acacia_leaves" ], + "drops": [ + { "weight": 1, "item": "unicopia:rotten_apple" }, + { "weight": 2, "item": "unicopia:sweet_apple" }, + { "weight": 5, "item": "unicopia:green_apple" } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/tree_types/birch.json b/src/main/resources/data/unicopia/tree_types/birch.json new file mode 100644 index 00000000..6f76b7e5 --- /dev/null +++ b/src/main/resources/data/unicopia/tree_types/birch.json @@ -0,0 +1,9 @@ +{ + "logs": [ "minecraft:birch_log", "minecraft:birch_wood" ], + "leaves": [ "minecraft:birch_leaves" ], + "drops": [ + { "weight": 1, "item": "unicopia:rotten_apple" }, + { "weight": 2, "item": "unicopia:sweet_apple" }, + { "weight": 5, "item": "unicopia:green_apple" } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/tree_types/dark_oak.json b/src/main/resources/data/unicopia/tree_types/dark_oak.json new file mode 100644 index 00000000..b8f0a424 --- /dev/null +++ b/src/main/resources/data/unicopia/tree_types/dark_oak.json @@ -0,0 +1,10 @@ +{ + "logs": [ "minecraft:dark_oak_log", "minecraft:dark_oak_wood" ], + "leaves": [ "minecraft:dark_oak_leaves" ], + "wideTrunk": true, + "drops": [ + { "weight": 1, "item": "unicopia:rottenn_apple" }, + { "weight": 2, "item": "unicopia:sweet_apple" }, + { "weight": 5, "item": "unicopia:zap_apple" } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/tree_types/jungle.json b/src/main/resources/data/unicopia/tree_types/jungle.json new file mode 100644 index 00000000..0bb47512 --- /dev/null +++ b/src/main/resources/data/unicopia/tree_types/jungle.json @@ -0,0 +1,10 @@ +{ + "logs": [ "minecraft:jungle_log", "minecraft:jungle_wood" ], + "leaves": [ "minecraft:jungle_leaves" ], + "wideTrunk": true, + "drops": [ + { "weight": 5, "item": "unicopia:green_apple" }, + { "weight": 2, "item": "unicopia:sweet_apple" }, + { "weight": 1, "item": "unicopia:zap_apple" } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/tree_types/oak.json b/src/main/resources/data/unicopia/tree_types/oak.json new file mode 100644 index 00000000..93db206f --- /dev/null +++ b/src/main/resources/data/unicopia/tree_types/oak.json @@ -0,0 +1,9 @@ +{ + "logs": [ "minecraft:oak_log", "minecraft:oak_wood" ], + "leaves": [ "minecraft:oak_leaves" ], + "drops": [ + { "weight": 1, "item": "unicopia:rotten_apple" }, + { "weight": 2, "item": "unicopia:green_apple" }, + { "weight": 3, "item": "minecraft:apple" } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/tree_types/spruce.json b/src/main/resources/data/unicopia/tree_types/spruce.json new file mode 100644 index 00000000..473c355e --- /dev/null +++ b/src/main/resources/data/unicopia/tree_types/spruce.json @@ -0,0 +1,10 @@ +{ + "logs": [ "minecraft:spruce_log", "minecraft:spruce_wood" ], + "leaves": [ "minecraft:spruce_leaves" ], + "wideTrunk": true, + "drops": [ + { "weight": 1, "item": "unicopia:sour_apple" }, + { "weight": 2, "item": "unicopia:green_apple" }, + { "weight": 4, "item": "unicopia:rotten_apple" } + ] +} \ No newline at end of file