diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java index b1dcf2a5..61ab54d5 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java @@ -1,9 +1,6 @@ package com.minelittlepony.unicopia.ability; -import java.util.HashSet; -import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.function.DoubleSupplier; import java.util.function.Supplier; import com.minelittlepony.unicopia.Race; @@ -12,12 +9,12 @@ import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Pos; import com.minelittlepony.unicopia.block.UBlocks; -import com.minelittlepony.unicopia.block.state.StateUtil; import com.minelittlepony.unicopia.entity.player.Pony; +import com.minelittlepony.unicopia.item.TransformCropsRecipe; +import com.minelittlepony.unicopia.item.URecipes; import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.server.world.BlockDestructionManager; -import com.minelittlepony.unicopia.server.world.UTreeGen; import com.minelittlepony.unicopia.util.TraceHelper; import com.minelittlepony.unicopia.util.VecHelper; @@ -33,7 +30,6 @@ import net.minecraft.particle.ParticleTypes; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.random.Random; import net.minecraft.world.World; import net.minecraft.world.WorldEvents; @@ -139,40 +135,41 @@ public class EarthPonyGrowAbility implements Ability { } private boolean applyDirectly(Pony player, BlockPos pos) { - return TransmutationRecipe.RECIPES.stream() - .filter(recipe -> recipe.matches(player.asWorld(), pos)) - .map(recipe -> recipe.checkPattern(player.asWorld(), pos)) - .filter(result -> result.matchedLocations().size() + 1 >= TransmutationRecipe.MINIMUM_INPUT) - .filter(result -> { - boolean transform = result.shoudTransform(player.asWorld().random); + return player.asWorld().getRecipeManager() + .getAllMatches(URecipes.GROWING, new TransformCropsRecipe.PlacementArea(player, pos), player.asWorld()) + .stream() + .map(recipe -> recipe.checkPattern(player.asWorld(), pos)) + .filter(result -> result.matchedLocations().size() + 1 >= TransformCropsRecipe.MINIMUM_INPUT) + .filter(result -> { + boolean transform = result.shoudTransform(player.asWorld().random); - player.playSound(USounds.ENTITY_CRYSTAL_SHARDS_AMBIENT, 1); + player.playSound(USounds.ENTITY_CRYSTAL_SHARDS_AMBIENT, 1); - result.matchedLocations().forEach(cell -> { - spawnConversionParticles(player.asWorld(), cell.up(), false); - BlockDestructionManager manager = BlockDestructionManager.of(player.asWorld()); - if (transform) { - if (manager.damageBlock(cell, 8) >= BlockDestructionManager.MAX_DAMAGE || player.asWorld().random.nextInt(20) == 0) { - player.asWorld().setBlockState(cell, Blocks.DIRT.getDefaultState()); - player.asWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, cell, Block.getRawIdFromState(player.asWorld().getBlockState(cell))); - } - } else { - if (manager.damageBlock(cell, 4) >= BlockDestructionManager.MAX_DAMAGE || player.asWorld().random.nextInt(20) == 0) { - player.asWorld().setBlockState(cell, Blocks.DIRT.getDefaultState()); - player.asWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, cell, Block.getRawIdFromState(player.asWorld().getBlockState(cell))); - } - } - }); - - spawnConversionParticles(player.asWorld(), pos, transform); + result.matchedLocations().forEach(cell -> { + spawnConversionParticles(player.asWorld(), cell.up(), false); + BlockDestructionManager manager = BlockDestructionManager.of(player.asWorld()); if (transform) { - player.asWorld().setBlockState(pos, result.recipe().getResult(player.asWorld(), pos)); + if (manager.damageBlock(cell, 8) >= BlockDestructionManager.MAX_DAMAGE || player.asWorld().random.nextInt(20) == 0) { + player.asWorld().setBlockState(cell, Blocks.DIRT.getDefaultState()); + player.asWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, cell, Block.getRawIdFromState(player.asWorld().getBlockState(cell))); + } + } else { + if (manager.damageBlock(cell, 4) >= BlockDestructionManager.MAX_DAMAGE || player.asWorld().random.nextInt(20) == 0) { + player.asWorld().setBlockState(cell, Blocks.DIRT.getDefaultState()); + player.asWorld().syncWorldEvent(WorldEvents.BLOCK_BROKEN, cell, Block.getRawIdFromState(player.asWorld().getBlockState(cell))); + } } + }); - return true; - }) - .findFirst() - .isPresent(); + spawnConversionParticles(player.asWorld(), pos, transform); + if (transform) { + player.asWorld().setBlockState(pos, result.recipe().getResult(player.asWorld(), pos)); + } + + return true; + }) + .findFirst() + .isPresent(); } private static void spawnConversionParticles(World w, BlockPos pos, boolean success) { @@ -201,48 +198,6 @@ public class EarthPonyGrowAbility implements Ability { } - private static record TransmutationRecipe(Block input, BlockState output, BlockState material) { - static final List RECIPES = List.of( - new TransmutationRecipe(Blocks.OAK_SAPLING, UTreeGen.GOLDEN_APPLE_TREE.sapling().get().getDefaultState(), Blocks.RAW_GOLD_BLOCK.getDefaultState()), - new TransmutationRecipe(Blocks.CARROTS, UBlocks.GOLD_ROOT.getDefaultState(), Blocks.RAW_GOLD_BLOCK.getDefaultState()), - new TransmutationRecipe(Blocks.CORNFLOWER, UBlocks.CURING_JOKE.getDefaultState(), Blocks.LAPIS_BLOCK.getDefaultState()), - new TransmutationRecipe(Blocks.WITHER_ROSE, UBlocks.PLUNDER_VINE_BUD.getDefaultState(), Blocks.NETHERRACK.getDefaultState()) - ); - static final int RADIUS = 3; - static final int SIDE_LENGTH = (2 * RADIUS) + 1; - static final int AREA = (SIDE_LENGTH * SIDE_LENGTH) - 1; - static final int MINIMUM_INPUT = 9; - - public boolean matches(World world, BlockPos pos) { - return world.getBlockState(pos).isOf(input); - } - - public Result checkPattern(World world, BlockPos pos) { - BlockPos center = pos.down(); - Set matches = new HashSet<>(); - for (BlockPos cell : BlockPos.iterateInSquare(center, RADIUS, Direction.EAST, Direction.NORTH)) { - if (cell.equals(center)) { - continue; - } - if (!world.getBlockState(cell).equals(material)) { - break; - } - matches.add(cell.toImmutable()); - } - return new Result(this, matches); - } - - public BlockState getResult(World world, BlockPos pos) { - return StateUtil.copyState(world.getBlockState(pos), output); - } - - record Result (TransmutationRecipe recipe, Set matchedLocations) { - public boolean shoudTransform(Random random) { - return random.nextInt(TransmutationRecipe.AREA) < matchedLocations().size(); - } - } - } - public interface Growable { boolean grow(World world, BlockState state, BlockPos pos); } diff --git a/src/main/java/com/minelittlepony/unicopia/compat/emi/Main.java b/src/main/java/com/minelittlepony/unicopia/compat/emi/Main.java index 01adac1f..4159d296 100644 --- a/src/main/java/com/minelittlepony/unicopia/compat/emi/Main.java +++ b/src/main/java/com/minelittlepony/unicopia/compat/emi/Main.java @@ -13,6 +13,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.block.UBlocks; import com.minelittlepony.unicopia.item.EnchantableItem; +import com.minelittlepony.unicopia.item.TransformCropsRecipe; import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.URecipes; import com.minelittlepony.unicopia.item.group.MultiItem; @@ -20,6 +21,7 @@ import com.minelittlepony.unicopia.item.group.MultiItem; import dev.emi.emi.api.EmiPlugin; import dev.emi.emi.api.EmiRegistry; import dev.emi.emi.api.recipe.EmiRecipeCategory; +import dev.emi.emi.api.recipe.EmiWorldInteractionRecipe; import dev.emi.emi.api.render.EmiTexture; import dev.emi.emi.api.stack.Comparison; import dev.emi.emi.api.stack.EmiStack; @@ -33,8 +35,10 @@ import net.minecraft.util.Identifier; public class Main implements EmiPlugin { static final EmiStack SPELL_BOOK_STATION = EmiStack.of(UItems.SPELLBOOK); static final EmiStack CLOUD_SHAPING_STATION = EmiStack.of(UBlocks.SHAPING_BENCH); + static final EmiStack GROWING_STATION = EmiStack.of(UItems.EARTH_BADGE); static final EmiRecipeCategory SPELL_BOOK_CATEGORY = new EmiRecipeCategory(Unicopia.id("spellbook"), SPELL_BOOK_STATION, SPELL_BOOK_STATION); static final EmiRecipeCategory CLOUD_SHAPING_CATEGORY = new EmiRecipeCategory(Unicopia.id("cloud_shaping"), CLOUD_SHAPING_STATION, CLOUD_SHAPING_STATION); + static final EmiRecipeCategory GROWING_CATEGORY = new EmiRecipeCategory(Unicopia.id("growing"), GROWING_STATION, GROWING_STATION); static final Identifier WIDGETS = Unicopia.id("textures/gui/widgets.png"); static final EmiTexture EMPTY_ARROW = new EmiTexture(WIDGETS, 44, 0, 24, 17); @@ -103,5 +107,20 @@ public class Main implements EmiPlugin { }); } }); + + registry.addCategory(GROWING_CATEGORY); + registry.addWorkstation(GROWING_CATEGORY, GROWING_STATION); + registry.getRecipeManager().listAllOfType(URecipes.GROWING).forEach(recipe -> { + registry.addRecipe(new EmiWorldInteractionRecipe(EmiWorldInteractionRecipe.builder() + .id(recipe.getId()) + .leftInput(EmiStack.of(recipe.getTargetAsItem())) + .rightInput(EmiStack.of(recipe.getCatalyst(), TransformCropsRecipe.MINIMUM_INPUT), true) + .output(EmiStack.of(recipe.getOutput()))) { + @Override + public EmiRecipeCategory getCategory() { + return GROWING_CATEGORY; + } + }); + }); } } diff --git a/src/main/java/com/minelittlepony/unicopia/item/TransformCropsRecipe.java b/src/main/java/com/minelittlepony/unicopia/item/TransformCropsRecipe.java new file mode 100644 index 00000000..284665ce --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/TransformCropsRecipe.java @@ -0,0 +1,176 @@ +package com.minelittlepony.unicopia.item; + +import java.util.HashSet; +import java.util.Set; + +import com.google.gson.JsonObject; +import com.minelittlepony.unicopia.block.state.StateUtil; +import com.minelittlepony.unicopia.entity.player.Pony; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.SingleStackInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.recipe.Recipe; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.recipe.RecipeType; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.registry.Registries; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.EmptyBlockView; +import net.minecraft.world.World; + +public class TransformCropsRecipe implements Recipe { + public static final int RADIUS = 3; + public static final int SIDE_LENGTH = (2 * RADIUS) + 1; + public static final int AREA = (SIDE_LENGTH * SIDE_LENGTH) - 1; + public static final int MINIMUM_INPUT = 9; + + private final Identifier id; + + private final Block target; + private final BlockState catalyst; + private final BlockState output; + + public TransformCropsRecipe(Identifier id, Block target, BlockState catalyst, BlockState output) { + this.id = id; + this.output = output; + this.target = target; + this.catalyst = catalyst; + } + + public ItemStack getTargetAsItem() { + return target.asItem().getDefaultStack(); + } + + public ItemStack getCatalyst() { + return catalyst.getBlock().getPickStack(EmptyBlockView.INSTANCE, BlockPos.ORIGIN, catalyst); + } + + public ItemStack getOutput() { + return output.getBlock().getPickStack(EmptyBlockView.INSTANCE, BlockPos.ORIGIN, output); + } + + @Override + public Identifier getId() { + return id; + } + + @Override + public RecipeSerializer getSerializer() { + return URecipes.TRANSFORM_CROP_SERIALIZER; + } + + @Override + public RecipeType getType() { + return URecipes.GROWING; + } + + @Override + public boolean matches(PlacementArea inventory, World world) { + return world.getBlockState(inventory.position()).isOf(target); + } + + @Override + public ItemStack craft(PlacementArea inventory, DynamicRegistryManager manager) { + return getOutput(manager); + } + + @Override + public ItemStack getOutput(DynamicRegistryManager manager) { + return output.getBlock().asItem().getDefaultStack(); + } + + public Result checkPattern(World world, BlockPos pos) { + BlockPos center = pos.down(); + Set matches = new HashSet<>(); + for (BlockPos cell : BlockPos.iterateInSquare(center, RADIUS, Direction.EAST, Direction.NORTH)) { + if (cell.equals(center)) { + continue; + } + if (!world.getBlockState(cell).equals(catalyst)) { + break; + } + matches.add(cell.toImmutable()); + } + return new Result(this, matches); + } + + public BlockState getResult(World world, BlockPos pos) { + return StateUtil.copyState(world.getBlockState(pos), output); + } + + @Override + public boolean fits(int width, int height) { + return width >= SIDE_LENGTH && height >= SIDE_LENGTH; + } + + public static class Serializer implements RecipeSerializer { + record Intermediate(Block target, BlockState fuel, BlockState output) {} + private static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Registries.BLOCK.getCodec().fieldOf("target").forGetter(Intermediate::target), + BlockState.CODEC.fieldOf("consume").forGetter(Intermediate::fuel), + BlockState.CODEC.fieldOf("output").forGetter(Intermediate::output) + ).apply(instance, Intermediate::new)); + + @Override + public TransformCropsRecipe read(Identifier id, JsonObject json) { + Intermediate content = CODEC.decode(JsonOps.INSTANCE, json).result().map(Pair::getFirst).get(); + return new TransformCropsRecipe(id, content.target(), content.fuel(), content.output()); + } + + @Override + public TransformCropsRecipe read(Identifier id, PacketByteBuf buffer) { + return new TransformCropsRecipe(id, + buffer.readRegistryValue(Registries.BLOCK), + Block.getStateFromRawId(buffer.readInt()), + Block.getStateFromRawId(buffer.readInt()) + ); + } + + @Override + public void write(PacketByteBuf buffer, TransformCropsRecipe recipe) { + buffer.writeRegistryValue(Registries.BLOCK, recipe.target); + buffer.writeInt(Block.getRawIdFromState(recipe.catalyst)); + buffer.writeInt(Block.getRawIdFromState(recipe.output)); + } + } + + public static record PlacementArea (Pony pony, BlockPos position) implements SingleStackInventory { + @Override + public ItemStack getStack(int var1) { + return ItemStack.EMPTY; + } + + @Override + public ItemStack removeStack(int slot, int count) { + return ItemStack.EMPTY; + } + + @Override + public void setStack(int slot, ItemStack stack) { } + + @Override + public void markDirty() { } + + @Override + public boolean canPlayerUse(PlayerEntity player) { + return true; + } + } + + public record Result (TransformCropsRecipe recipe, Set matchedLocations) { + public boolean shoudTransform(Random random) { + return random.nextInt(AREA) < matchedLocations().size(); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/UItems.java b/src/main/java/com/minelittlepony/unicopia/item/UItems.java index a5ede2a8..3aa1e5ea 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/item/UItems.java @@ -48,6 +48,7 @@ public interface UItems { FriendshipBraceletItem FRIENDSHIP_BRACELET = register("friendship_bracelet", new FriendshipBraceletItem(new FabricItemSettings().rarity(Rarity.UNCOMMON)), ItemGroups.TOOLS); + Item PLUNDER_VINE = register("plunder_vine", new BlockItem(UBlocks.PLUNDER_VINE_BUD, new Item.Settings())); Item EMPTY_JAR = register("empty_jar", new JarItem(new Item.Settings().maxCount(16).fireproof(), false, false, false), ItemGroups.FUNCTIONAL); FilledJarItem FILLED_JAR = register("filled_jar", new FilledJarItem(new Item.Settings().maxCount(1).recipeRemainder(EMPTY_JAR))); Item RAIN_CLOUD_JAR = register("rain_cloud_jar", new JarItem(new Item.Settings().maxCount(1).fireproof().recipeRemainder(EMPTY_JAR), true, false, false), ItemGroups.FUNCTIONAL); diff --git a/src/main/java/com/minelittlepony/unicopia/item/URecipes.java b/src/main/java/com/minelittlepony/unicopia/item/URecipes.java index 2c0a8573..497e6d6c 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/URecipes.java +++ b/src/main/java/com/minelittlepony/unicopia/item/URecipes.java @@ -23,6 +23,7 @@ import net.minecraft.util.collection.DefaultedList; public interface URecipes { RecipeType SPELLBOOK = RecipeType.register("unicopia:spellbook"); RecipeType CLOUD_SHAPING = RecipeType.register("unicopia:cloud_shaping"); + RecipeType GROWING = RecipeType.register("unicopia:growing"); RecipeSerializer ZAP_APPLE_SERIALIZER = RecipeSerializer.register("unicopia:crafting_zap_apple", new ZapAppleRecipe.Serializer()); RecipeSerializer GLOWING_SERIALIZER = RecipeSerializer.register("unicopia:crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new)); @@ -33,6 +34,7 @@ public interface URecipes { RecipeSerializer TRAIT_COMBINING = RecipeSerializer.register("unicopia:spellbook/combining", new SpellEnhancingRecipe.Serializer()); RecipeSerializer SPELL_DUPLICATING = RecipeSerializer.register("unicopia:spellbook/duplicating", new SpellDuplicatingRecipe.Serializer()); RecipeSerializer CLOUD_SHAPING_SERIALIZER = RecipeSerializer.register("unicopia:cloud_shaping", new CuttingRecipe.Serializer<>(CloudShapingRecipe::new) {}); + RecipeSerializer TRANSFORM_CROP_SERIALIZER = RecipeSerializer.register("unicopia:transform_crop", new TransformCropsRecipe.Serializer()); static DefaultedList getIngredients(JsonArray json) { DefaultedList defaultedList = DefaultedList.of(); diff --git a/src/main/resources/assets/unicopia/lang/en_us.json b/src/main/resources/assets/unicopia/lang/en_us.json index f409a35f..fe83a05b 100644 --- a/src/main/resources/assets/unicopia/lang/en_us.json +++ b/src/main/resources/assets/unicopia/lang/en_us.json @@ -46,6 +46,7 @@ "item.unicopia.spellbook": "Spellbook", "emi.category.unicopia.spellbook": "Spellbook", "emi.category.unicopia.cloud_shaping": "Shaping", + "emi.category.unicopia.growing": "Growing", "item.unicopia.alicorn_badge": "Alicorn Emblem", "item.unicopia.unicorn_badge": "Unicorn Emblem", @@ -73,6 +74,7 @@ "item.unicopia.love_bucket": "Love Bucket", "item.unicopia.love_mug": "Mug o' Love", + "item.unicopia.plunder_vine": "Plunder Vine", "item.unicopia.empty_jar": "Glass Jar", "item.unicopia.filled_jar": "%s in a Jar", "item.unicopia.rain_cloud_jar": "Rain in a Jar", diff --git a/src/main/resources/assets/unicopia/models/item/plunder_vine.json b/src/main/resources/assets/unicopia/models/item/plunder_vine.json new file mode 100644 index 00000000..32b343c6 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/plunder_vine.json @@ -0,0 +1,3 @@ +{ + "parent": "unicopia:block/plunder_vine_bud" +} diff --git a/src/main/resources/data/unicopia/recipes/growing/curing_joke.json b/src/main/resources/data/unicopia/recipes/growing/curing_joke.json new file mode 100644 index 00000000..61625b41 --- /dev/null +++ b/src/main/resources/data/unicopia/recipes/growing/curing_joke.json @@ -0,0 +1,12 @@ +{ + "type": "unicopia:transform_crop", + "target": "minecraft:cornflower", + "consume": { + "Name": "minecraft:lapis_block", + "Properties": {} + }, + "output": { + "Name": "unicopia:curing_joke", + "Properties": {} + } +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/recipes/growing/gold_root.json b/src/main/resources/data/unicopia/recipes/growing/gold_root.json new file mode 100644 index 00000000..a6d2d09b --- /dev/null +++ b/src/main/resources/data/unicopia/recipes/growing/gold_root.json @@ -0,0 +1,12 @@ +{ + "type": "unicopia:transform_crop", + "target": "minecraft:carrots", + "consume": { + "Name": "minecraft:raw_gold_block", + "Properties": {} + }, + "output": { + "Name": "unicopia:gold_root", + "Properties": {} + } +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/recipes/growing/golden_oak_sapling.json b/src/main/resources/data/unicopia/recipes/growing/golden_oak_sapling.json new file mode 100644 index 00000000..b129e3ae --- /dev/null +++ b/src/main/resources/data/unicopia/recipes/growing/golden_oak_sapling.json @@ -0,0 +1,12 @@ +{ + "type": "unicopia:transform_crop", + "target": "minecraft:oak_sapling", + "consume": { + "Name": "minecraft:raw_gold_block", + "Properties": {} + }, + "output": { + "Name": "unicopia:golden_oak_sapling", + "Properties": {} + } +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/recipes/growing/plunder_vine.json b/src/main/resources/data/unicopia/recipes/growing/plunder_vine.json new file mode 100644 index 00000000..df6a6eac --- /dev/null +++ b/src/main/resources/data/unicopia/recipes/growing/plunder_vine.json @@ -0,0 +1,12 @@ +{ + "type": "unicopia:transform_crop", + "target": "minecraft:wither_rose", + "consume": { + "Name": "minecraft:netherrack", + "Properties": {} + }, + "output": { + "Name": "unicopia:plunder_vine_bud", + "Properties": {} + } +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/recipes/growing/zapling.json b/src/main/resources/data/unicopia/recipes/growing/zapling.json new file mode 100644 index 00000000..971c2099 --- /dev/null +++ b/src/main/resources/data/unicopia/recipes/growing/zapling.json @@ -0,0 +1,12 @@ +{ + "type": "unicopia:transform_crop", + "target": "minecraft:dark_oak_sapling", + "consume": { + "Name": "unicopia:chitin", + "Properties": {} + }, + "output": { + "Name": "unicopia:zapling", + "Properties": {} + } +} \ No newline at end of file diff --git a/src/main/resources/data/unicopia/tags/items/has_no_traits.json b/src/main/resources/data/unicopia/tags/items/has_no_traits.json index c29a2af1..1a300515 100644 --- a/src/main/resources/data/unicopia/tags/items/has_no_traits.json +++ b/src/main/resources/data/unicopia/tags/items/has_no_traits.json @@ -15,6 +15,7 @@ "minecraft:end_portal_frame", "minecraft:debug_stick", "minecraft:command_block_minecart", + "unicopia:plunder_vine", "#unicopia:badges" ] }