diff --git a/README.md b/README.md index 9a15df216..87256b95e 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,11 @@

- - Scc Count Badge - Ask DeepWiki - Gitbook + Gitbook

@@ -55,7 +52,7 @@ The code you contribute will be open-sourced under the GPLv3 license. If you pre ### 🌍 Translations 1. Clone this repository. 2. Create a new language file in: `/common-files/src/main/resources/translations` -3. Once done, submit a **pull request** for review. We appreciate your contributions! +3. Once done, submit a **pull request** to **dev** branch for review. We appreciate your contributions! ## Differences Between Versions | Version | Official Support | Max Players | Dev Builds | @@ -79,7 +76,7 @@ repositories { ``` ```kotlin dependencies { - compileOnly("net.momirealms:craft-engine-core:0.0.56") - compileOnly("net.momirealms:craft-engine-bukkit:0.0.56") + compileOnly("net.momirealms:craft-engine-core:0.0.57") + compileOnly("net.momirealms:craft-engine-bukkit:0.0.57") } ``` \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 388c37cc5..25838c89e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,7 +27,7 @@ subprojects { expand(rootProject.properties) } - filesMatching(arrayListOf("commands.yml", "config.yml", "*/*.yml", "ignite.mod.json")) { + filesMatching(arrayListOf("commands.yml", "config.yml")) { expand( Pair("project_version", rootProject.properties["project_version"]), Pair("config_version", rootProject.properties["config_version"]), diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts index 55151de14..e995978d5 100644 --- a/bukkit/compatibility/build.gradle.kts +++ b/bukkit/compatibility/build.gradle.kts @@ -7,7 +7,7 @@ repositories { maven("https://repo.rapture.pw/repository/maven-releases/") // slime world maven("https://repo.infernalsuite.com/repository/maven-snapshots/") // slime world maven("https://repo.momirealms.net/releases/") - maven("https://mvn.lumine.io/repository/maven-public/") // model engine + maven("https://mvn.lumine.io/repository/maven-public/") // model engine mythic mobs maven("https://nexus.phoenixdevt.fr/repository/maven-public/") // mmoitems maven("https://repo.viaversion.com") // via maven("https://repo.skriptlang.org/releases/") // skript @@ -47,6 +47,8 @@ dependencies { compileOnly(platform("com.intellectualsites.bom:bom-newest:1.52")) compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Core") compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Bukkit") { isTransitive = false } + // MythicMobs + compileOnly("io.lumine:Mythic-Dist:5.9.0") } java { diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java index 680455c0a..049efa25f 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java @@ -3,11 +3,13 @@ package net.momirealms.craftengine.bukkit.compatibility; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.compatibility.bettermodel.BetterModelModel; import net.momirealms.craftengine.bukkit.compatibility.item.MMOItemsProvider; +import net.momirealms.craftengine.bukkit.compatibility.item.MythicMobsProvider; import net.momirealms.craftengine.bukkit.compatibility.item.NeigeItemsProvider; import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor; import net.momirealms.craftengine.bukkit.compatibility.leveler.AuraSkillsLevelerProvider; import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineModel; import net.momirealms.craftengine.bukkit.compatibility.modelengine.ModelEngineUtils; +import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicMobsListener; import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners; import net.momirealms.craftengine.bukkit.compatibility.skript.SkriptHook; @@ -104,6 +106,12 @@ public class BukkitCompatibilityManager implements CompatibilityManager { } if (this.isPluginEnabled("AuraSkills")) { this.registerLevelerProvider("AuraSkills", new AuraSkillsLevelerProvider()); + logHook("AuraSkills"); + } + if (this.isPluginEnabled("MythicMobs")) { + BukkitItemManager.instance().registerExternalItemProvider(new MythicMobsProvider()); + new MythicMobsListener(this.plugin); + logHook("MythicMobs"); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MythicMobsProvider.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MythicMobsProvider.java new file mode 100644 index 000000000..8b01bc237 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MythicMobsProvider.java @@ -0,0 +1,25 @@ +package net.momirealms.craftengine.bukkit.compatibility.item; + +import io.lumine.mythic.bukkit.MythicBukkit; +import net.momirealms.craftengine.core.item.ExternalItemProvider; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; + +public class MythicMobsProvider implements ExternalItemProvider { + private MythicBukkit mythicBukkit; + + @Override + public String plugin() { + return "MythicMobs"; + } + + @Nullable + @Override + public ItemStack build(String id, ItemBuildContext context) { + if (mythicBukkit == null || mythicBukkit.isClosed()) { + this.mythicBukkit = MythicBukkit.inst(); + } + return mythicBukkit.getItemManager().getItemStack(id); + } +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/CraftEngineItemDrop.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/CraftEngineItemDrop.java new file mode 100644 index 000000000..8c144b4c5 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/CraftEngineItemDrop.java @@ -0,0 +1,64 @@ +package net.momirealms.craftengine.bukkit.compatibility.mythicmobs; + +import io.lumine.mythic.api.adapters.AbstractItemStack; +import io.lumine.mythic.api.adapters.AbstractPlayer; +import io.lumine.mythic.api.config.MythicLineConfig; +import io.lumine.mythic.api.drops.DropMetadata; +import io.lumine.mythic.api.drops.IItemDrop; +import io.lumine.mythic.api.skills.SkillCaster; +import io.lumine.mythic.bukkit.BukkitAdapter; +import io.lumine.mythic.bukkit.adapters.BukkitItemStack; +import io.lumine.mythic.core.drops.droppables.ItemDrop; +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.ReflectionUtils; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.Constructor; + +public class CraftEngineItemDrop extends ItemDrop implements IItemDrop { + private final CustomItem customItem; + private static final Constructor constructor$BukkitItemStack = ReflectionUtils.getConstructor(BukkitItemStack.class, ItemStack.class); + private static final boolean useReflection = constructor$BukkitItemStack != null; + + public CraftEngineItemDrop(String line, MythicLineConfig config, CustomItem customItem) { + super(line, config); + this.customItem = customItem; + CraftEngine.instance().debug(() -> "[MM调试] " + customItem.id() + " 注册成功"); + } + + @Override + public AbstractItemStack getDrop(DropMetadata dropMetadata, double amount) { + CraftEngine.instance().debug(() -> "[MM调试] getDrop() dropMetadata={" + dropMetadata + "}, amount={" + amount + "}"); + ItemBuildContext context = ItemBuildContext.EMPTY; + SkillCaster caster = dropMetadata.getCaster(); + if (caster != null && caster.getEntity() instanceof AbstractPlayer abstractPlayer) { + Entity bukkitEntity = abstractPlayer.getBukkitEntity(); + if (bukkitEntity instanceof Player bukkitPlayer) { + var player = BukkitCraftEngine.instance().adapt(bukkitPlayer); + context = ItemBuildContext.of(player); + } + } + int amountInt = MCUtils.fastFloor(amount + 0.5F); + ItemStack itemStack = this.customItem.buildItemStack(context, amountInt); + return adapt(itemStack).amount(amountInt); + } + + private static AbstractItemStack adapt(ItemStack itemStack) { + if (useReflection) { + try { + return (AbstractItemStack) constructor$BukkitItemStack.newInstance(itemStack); + } catch (Exception e) { + CraftEngine.instance().logger().warn("adapt(ItemStack itemStack) error: " + e.getMessage()); + return null; + } + } else { + return BukkitAdapter.adapt(itemStack); + } + } +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicMobsListener.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicMobsListener.java new file mode 100644 index 000000000..9d59cab3a --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicMobsListener.java @@ -0,0 +1,31 @@ +package net.momirealms.craftengine.bukkit.compatibility.mythicmobs; + +import io.lumine.mythic.api.config.MythicLineConfig; +import io.lumine.mythic.bukkit.events.MythicDropLoadEvent; +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class MythicMobsListener implements Listener { + private final BukkitCraftEngine plugin; + + public MythicMobsListener(BukkitCraftEngine plugin) { + this.plugin = plugin; + Bukkit.getPluginManager().registerEvents(this, plugin.javaPlugin()); + } + + @EventHandler + public void onMythicDropLoad(MythicDropLoadEvent event) { + if (!event.getDropName().equalsIgnoreCase("craftengine")) return; + String argument = event.getArgument(); + plugin.debug(() -> "[MM调试] " + argument); + Key itemId = Key.of(argument); + this.plugin.itemManager().getCustomItem(itemId).ifPresent(customItem -> { + String line = event.getContainer().getConfigLine(); + MythicLineConfig config = event.getConfig(); + event.register(new CraftEngineItemDrop(line, config, customItem)); + }); + } +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/ImageExpansion.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/ImageExpansion.java index c6ac983c1..e86171c4c 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/ImageExpansion.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/ImageExpansion.java @@ -59,6 +59,8 @@ public class ImageExpansion extends PlaceholderExpansion { int codepoint; if (param.length == 4) { codepoint = image.codepointAt(Integer.parseInt(param[2]), Integer.parseInt(param[3])); + } else if (param.length == 3) { + codepoint = image.codepointAt(Integer.parseInt(param[2]), 0); } else if (param.length == 2) { codepoint = image.codepointAt(0,0); } else { diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprCustomItem.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprCustomItem.java index 2c3557a47..aacfe01ff 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprCustomItem.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprCustomItem.java @@ -7,14 +7,13 @@ import ch.njol.skript.lang.SkriptParser; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.util.Kleenean; import net.momirealms.craftengine.bukkit.api.CraftEngineItems; +import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.util.Key; import org.bukkit.event.Event; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; -import java.util.Objects; - public class ExprCustomItem extends SimpleExpression { public static void register() { @@ -36,7 +35,8 @@ public class ExprCustomItem extends SimpleExpression { String itemId = this.itemId.getSingle(e); if (itemId == null) return null; - return new ItemStack[] {Objects.requireNonNull(CraftEngineItems.byId(Key.of(itemId))).buildItemStack(ItemBuildContext.EMPTY)}; + CustomItem customItem = CraftEngineItems.byId(Key.of(itemId)); + return customItem == null ? null : new ItemStack[] {customItem.buildItemStack(ItemBuildContext.EMPTY)}; } @Override diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java index f11a78ac1..bd3d4b988 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/expression/ExprEntityFurnitureID.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import org.bukkit.entity.Entity; import org.jetbrains.annotations.Nullable; -import java.util.Objects; +import java.util.Optional; public class ExprEntityFurnitureID extends SimplePropertyExpression { @@ -15,8 +15,11 @@ public class ExprEntityFurnitureID extends SimplePropertyExpression it.id().toString()) + .orElse(null); + } return null; } diff --git a/bukkit/paper-loader/build.gradle.kts b/bukkit/paper-loader/build.gradle.kts index 4141b43ee..9c8b6b480 100644 --- a/bukkit/paper-loader/build.gradle.kts +++ b/bukkit/paper-loader/build.gradle.kts @@ -71,27 +71,47 @@ paper { required = false load = PaperPluginDescription.RelativeLoadOrder.BEFORE } - register("NeigeItems") { - required = false - } - register("MMOItems") { - required = false - } - register("ModelEngine") { - required = false - } - register("BetterModel") { - required = false - } - register("AuraSkills") { - required = false - } - register("LuckPerms") { - required = false - } - register("ViaVersion") { - required = false - } + register("LuckPerms") { required = false } + register("ViaVersion") { required = false } + + // external models + register("ModelEngine") { required = false } + register("BetterModel") { required = false } + + // external items + register("NeigeItems") { required = false } + register("MMOItems") { required = false } + register("MythicMobs") { required = false } + + // leveler + register("AuraSkills") { required = false } + + // anti grief lib + register("Dominion") { required = false } + register("WorldGuard") { required = false } + register("Kingdoms") { required = false } + register("Lands") { required = false } + register("IridiumSkyblock") { required = false } + register("CrashClaim") { required = false } + register("GriefDefender") { required = false } + register("HuskClaims") { required = false } + register("BentoBox") { required = false } + register("HuskTowns") { required = false } + register("PlotSquared") { required = false } + register("Residence") { required = false } + register("SuperiorSkyblock2") { required = false } + register("Towny") { required = false } + register("FabledSkyBlock") { required = false } + register("GriefPrevention") { required = false } + register("RedProtect") { required = false } + register("Landlord") { required = false } + register("uSkyBlock") { required = false } + register("XClaim") { required = false } + register("UltimateClaims") { required = false } + register("UltimateClans") { required = false } + register("PreciousStones") { required = false } + register("hClaims") { required = false } + register("Factions") { required = false } } } diff --git a/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEngineBootstrap.java b/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEngineBootstrap.java index 1af1956bf..aadff5866 100644 --- a/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEngineBootstrap.java +++ b/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEngineBootstrap.java @@ -50,6 +50,7 @@ public class PaperCraftEngineBootstrap implements PluginBootstrap { new ModernEventHandler(context, this.plugin).register(); } else { try { + logger.info("Patching the server..."); RuntimePatcher.patch(this.plugin); } catch (Exception e) { throw new RuntimeException("Failed to patch server", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java index e899291a4..c80db2fe4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java @@ -52,7 +52,7 @@ public final class CraftEngineFurniture { public static BukkitFurniture place(Location location, Key furnitureId) { CustomFurniture furniture = byId(furnitureId); if (furniture == null) return null; - return place(location, furnitureId, furniture.getAnyPlacement()); + return place(location, furnitureId, furniture.getAnyAnchorType()); } /** diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index f20cdcca1..3cefc336a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -28,7 +28,6 @@ import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.*; import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -371,19 +370,18 @@ public class BlockEventListener implements Listener { // for vanilla blocks if (event.getChangedType() == Material.NOTE_BLOCK) { Block block = event.getBlock(); - World world = block.getWorld(); - Location location = block.getLocation(); Block sourceBlock = event.getSourceBlock(); - BlockFace direction = sourceBlock.getFace(block); - if (direction == BlockFace.UP || direction == BlockFace.DOWN) { + if (block.getX() == sourceBlock.getX() && block.getX() == sourceBlock.getZ()) { + World world = block.getWorld(); + Location location = block.getLocation(); Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world); Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel); Object blockPos = LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos); - if (direction == BlockFace.UP) { - NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$UP, blockPos, 0); + if (block.getY() > sourceBlock.getY()) { + NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$UP, blockPos, Config.maxNoteBlockChainUpdate()); } else { - NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$DOWN, blockPos, 0); + NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$DOWN, blockPos, Config.maxNoteBlockChainUpdate()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index ed6627210..d9853e3c9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -19,6 +19,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.RegistryUtils; @@ -31,7 +32,6 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; @@ -45,7 +45,6 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -93,10 +92,8 @@ public class BukkitBlockManager extends AbstractBlockManager { this.blockParser = new BlockParser(); this.initVanillaRegistry(); this.loadMappingsAndAdditionalBlocks(); - if (!plugin.requiresRestart()) { - this.registerBlocks(); - this.registerEmptyBlock(); - } + this.registerBlocks(); + this.registerEmptyBlock(); } @Override @@ -163,9 +160,9 @@ public class BukkitBlockManager extends AbstractBlockManager { for (Map.Entry> entry : this.clientBoundTags.entrySet()) { list.add(new TagUtils.TagEntry(entry.getKey(), entry.getValue())); } - Object packet = TagUtils.createUpdateTagsPacket(Map.of(MRegistries.instance$Registries$BLOCK, list)); - for (Player player : Bukkit.getOnlinePlayers()) { - this.plugin.networkManager().sendPacket(this.plugin.adapt(player), packet); + Object packet = TagUtils.createUpdateTagsPacket(Map.of(MRegistries.BLOCK, list)); + for (BukkitServerPlayer player : this.plugin.networkManager().onlineUsers()) { + player.sendPacket(packet, false); } // 如果空,那么新来的玩家就没必要收到更新包了 if (list.isEmpty()) { @@ -276,19 +273,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } private void initVanillaRegistry() { - int vanillaStateCount; - if (this.plugin.hasMod()) { - try { - Class modClass = ReflectionUtils.getClazz(CraftEngine.MOD_CLASS); - Field amountField = ReflectionUtils.getDeclaredField(modClass, "vanillaRegistrySize"); - vanillaStateCount = amountField.getInt(null); - } catch (Exception e) { - vanillaStateCount = RegistryUtils.currentBlockRegistrySize(); - this.plugin.logger().severe("Fatal error", e); - } - } else { - vanillaStateCount = RegistryUtils.currentBlockRegistrySize(); - } + int vanillaStateCount = RegistryUtils.currentBlockRegistrySize(); this.plugin.logger().info("Vanilla block count: " + vanillaStateCount); BlockStateUtils.init(vanillaStateCount); } @@ -350,7 +335,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } public class BlockParser implements ConfigParser { - public static final String[] CONFIG_SECTION_NAME = new String[] {"blocks", "block"}; + public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; @Override public String[] sectionId() { @@ -512,10 +497,13 @@ public class BukkitBlockManager extends AbstractBlockManager { throw new LocalizedResourceConfigException("warning.config.block.state.model.invalid_path", modelPath); } json.addProperty("model", modelPath); - if (singleModelMap.containsKey("x")) json.addProperty("x", ResourceConfigUtils.getAsInt(singleModelMap.get("x"), "x")); - if (singleModelMap.containsKey("y")) json.addProperty("y", ResourceConfigUtils.getAsInt(singleModelMap.get("y"), "y")); + if (singleModelMap.containsKey("x")) + json.addProperty("x", ResourceConfigUtils.getAsInt(singleModelMap.get("x"), "x")); + if (singleModelMap.containsKey("y")) + json.addProperty("y", ResourceConfigUtils.getAsInt(singleModelMap.get("y"), "y")); if (singleModelMap.containsKey("uvlock")) json.addProperty("uvlock", (boolean) singleModelMap.get("uvlock")); - if (singleModelMap.containsKey("weight")) json.addProperty("weight", ResourceConfigUtils.getAsInt(singleModelMap.get("weight"), "weight")); + if (singleModelMap.containsKey("weight")) + json.addProperty("weight", ResourceConfigUtils.getAsInt(singleModelMap.get("weight"), "weight")); Map generationMap = MiscUtils.castToMap(singleModelMap.get("generation"), true); if (generationMap != null) { prepareModelGeneration(ModelGeneration.of(Key.of(modelPath), generationMap)); @@ -591,6 +579,7 @@ public class BukkitBlockManager extends AbstractBlockManager { Object resourceLocation = KeyUtils.toResourceLocation(BlockKeys.NOTE_BLOCK); Object block = CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, resourceLocation); Object stateDefinition = CoreReflections.field$Block$StateDefinition.get(block); + @SuppressWarnings("unchecked") ImmutableList states = (ImmutableList) CoreReflections.field$StateDefinition$states.get(stateDefinition); for (Object state : states) { BlockStateUtils.CLIENT_SIDE_NOTE_BLOCKS.put(state, new Object()); @@ -723,29 +712,20 @@ public class BukkitBlockManager extends AbstractBlockManager { Object blockHolder; Object resourceLocation = createResourceLocation(realBlockKey); - if (this.plugin.hasMod()) { - newRealBlock = CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, resourceLocation); - newBlockState = getOnlyBlockState(newRealBlock); - - @SuppressWarnings("unchecked") - Optional optionalHolder = (Optional) CoreReflections.method$Registry$getHolder1.invoke(MBuiltInRegistries.BLOCK, CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.instance$Registries$BLOCK, resourceLocation)); - blockHolder = optionalHolder.get(); - } else { - try { - newRealBlock = BlockGenerator.generateBlock(clientSideBlockType, clientSideBlock, blockProperties); - } catch (Throwable throwable) { - this.plugin.logger().warn("Failed to generate dynamic block class", throwable); - continue; - } - - blockHolder = CoreReflections.method$Registry$registerForHolder.invoke(null, MBuiltInRegistries.BLOCK, resourceLocation, newRealBlock); - CoreReflections.method$Holder$Reference$bindValue.invoke(blockHolder, newRealBlock); - CoreReflections.field$Holder$Reference$tags.set(blockHolder, Set.of()); - - newBlockState = getOnlyBlockState(newRealBlock); - CoreReflections.method$IdMapper$add.invoke(CoreReflections.instance$Block$BLOCK_STATE_REGISTRY, newBlockState); + try { + newRealBlock = BlockGenerator.generateBlock(clientSideBlockType, clientSideBlock, blockProperties); + } catch (Throwable throwable) { + this.plugin.logger().warn("Failed to generate dynamic block class", throwable); + continue; } + blockHolder = CoreReflections.method$Registry$registerForHolder.invoke(null, MBuiltInRegistries.BLOCK, resourceLocation, newRealBlock); + CoreReflections.method$Holder$Reference$bindValue.invoke(blockHolder, newRealBlock); + CoreReflections.field$Holder$Reference$tags.set(blockHolder, Set.of()); + + newBlockState = getOnlyBlockState(newRealBlock); + CoreReflections.method$IdMapper$add.invoke(CoreReflections.instance$Block$BLOCK_STATE_REGISTRY, newBlockState); + if (isNoteBlock) { BlockStateUtils.CLIENT_SIDE_NOTE_BLOCKS.put(newBlockState, new Object()); } @@ -782,7 +762,7 @@ public class BukkitBlockManager extends AbstractBlockManager { private Object createBlockProperties(Key realBlockKey) throws Exception { Object blockProperties = CoreReflections.method$BlockBehaviour$Properties$of.invoke(null); Object realBlockResourceLocation = createResourceLocation(realBlockKey); - Object realBlockResourceKey = CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.instance$Registries$BLOCK, realBlockResourceLocation); + Object realBlockResourceKey = CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.BLOCK, realBlockResourceLocation); if (CoreReflections.field$BlockBehaviour$Properties$id != null) { CoreReflections.field$BlockBehaviour$Properties$id.set(blockProperties, realBlockResourceKey); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java index dfac86a24..b2da03528 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlock.java @@ -129,13 +129,12 @@ public class BukkitCustomBlock extends AbstractCustomBlock { // init cache CoreReflections.method$BlockStateBase$initCache.invoke(mcBlockState); // set block light - if (settings.blockLight() != -1) { - if (VersionHelper.isOrAbove1_21_2()) { - CoreReflections.field$BlockStateBase$lightBlock.set(mcBlockState, settings.blockLight()); - } else { - Object cache = CoreReflections.field$BlockStateBase$cache.get(mcBlockState); - CoreReflections.field$BlockStateBase$Cache$lightBlock.set(cache, settings.blockLight()); - } + int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(state.vanillaBlockState().handle()); + if (VersionHelper.isOrAbove1_21_2()) { + CoreReflections.field$BlockStateBase$lightBlock.set(mcBlockState, blockLight); + } else { + Object cache = CoreReflections.field$BlockStateBase$cache.get(mcBlockState); + CoreReflections.field$BlockStateBase$Cache$lightBlock.set(cache, blockLight); } // set fluid later if (settings.fluidState()) { @@ -151,7 +150,7 @@ public class BukkitCustomBlock extends AbstractCustomBlock { Object holder = BukkitCraftEngine.instance().blockManager().getMinecraftBlockHolder(state.customBlockState().registryId()); Set tags = new HashSet<>(); for (Key tag : settings.tags()) { - tags.add(CoreReflections.method$TagKey$create.invoke(null, MRegistries.instance$Registries$BLOCK, KeyUtils.toResourceLocation(tag))); + tags.add(CoreReflections.method$TagKey$create.invoke(null, MRegistries.BLOCK, KeyUtils.toResourceLocation(tag))); } CoreReflections.field$Holder$Reference$tags.set(holder, tags); // set burning properties diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java index 8b30ef6b3..75d0ebf53 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AbstractCanSurviveBlockBehavior.java @@ -65,7 +65,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio public void onPlace(Object thisBlock, Object[] args, Callable superMethod) throws Exception { Object world = args[1]; Object blockPos = args[2]; - CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2); + FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 2); } @Override @@ -86,7 +86,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio return state; } if (this.delay != 0) { - CoreReflections.method$LevelAccessor$scheduleTick.invoke(level, blockPos, thisBlock, this.delay); + FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(level, blockPos, thisBlock, this.delay); return state; } if (!canSurvive(thisBlock, new Object[] {state, level, blockPos}, () -> true)) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java index f04aed908..3e7cc6771 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java @@ -36,7 +36,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { public void onPlace(Object thisBlock, Object[] args, Callable superMethod) throws Exception { Object world = args[1]; Object blockPos = args[2]; - CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2); + FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 2); } @Override @@ -50,7 +50,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { world = args[3]; blockPos = args[4]; } - CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 2); + FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 2); return args[0]; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java index 3be6e4894..ddf3a3c64 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LampBlockBehavior.java @@ -62,7 +62,7 @@ public class LampBlockBehavior extends BukkitBlockBehavior { boolean lit = state.get(this.litProperty); if (lit != FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) { if (lit) { - CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 4); + FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 4); } else { // TODO Call Event FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, state.cycle(this.litProperty).customBlockState().handle(), 2); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java index 1914f43cc..29d203086 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java @@ -85,7 +85,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { LeavesBlockBehavior behavior = optionalBehavior.get(); int distance = behavior.getDistanceAt(neighborState) + 1; if (distance != 1 || behavior.getDistance(thisState) != distance) { - CoreReflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 1); + FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(world, blockPos, thisBlock, 1); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java index acee6a957..8569e6ca9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java @@ -77,7 +77,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior { } private void generateTree(Object world, Object blockPos, Object blockState, Object randomSource) throws Exception { - Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.instance$Registries$CONFIGURED_FEATURE); + Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.CONFIGURED_FEATURE); if (registry == null) return; @SuppressWarnings("unchecked") Optional holder = (Optional) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createFeatureKey(treeFeature())); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java index 183a0578d..a40c5923e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java @@ -7,20 +7,21 @@ public interface EntityData { Object serializer(); int id(); T defaultValue(); + Object entityDataAccessor(); default Object createEntityDataIfNotDefaultValue(T value) { if (defaultValue().equals(value)) return null; - return EntityDataValue.create(id(), serializer(), value); + return EntityDataValue.create(id(), serializer(), entityDataAccessor(), value); } default void addEntityDataIfNotDefaultValue(T value, List list) { if (!defaultValue().equals(value)) { - list.add(EntityDataValue.create(id(), serializer(), value)); + list.add(EntityDataValue.create(id(), serializer(), entityDataAccessor(), value)); } } default void addEntityData(T value, List list) { - list.add(EntityDataValue.create(id(), serializer(), value)); + list.add(EntityDataValue.create(id(), serializer(), entityDataAccessor(), value)); } static EntityData of(int id, Object serializer, T defaultValue) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java index 064983cdf..fee5d034f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java @@ -98,8 +98,7 @@ public class EntityDataValue { throw new IllegalAccessError("Utility class"); } - public static Object create(int id, Object serializer, Object value) { - Object entityDataAccessor = FastNMS.INSTANCE.constructor$EntityDataAccessor(id, serializer); + public static Object create(int id, Object serializer, Object entityDataAccessor, Object value) { return FastNMS.INSTANCE.method$SynchedEntityData$DataValue$create(entityDataAccessor, value); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/SimpleEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/SimpleEntityData.java index 7993ed163..ae96ccc3a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/SimpleEntityData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/SimpleEntityData.java @@ -1,14 +1,18 @@ package net.momirealms.craftengine.bukkit.entity.data; +import net.momirealms.craftengine.bukkit.nms.FastNMS; + public class SimpleEntityData implements EntityData { private final int id; private final Object serializer; private final T defaultValue; + private final Object entityDataAccessor; public SimpleEntityData(int id, Object serializer, T defaultValue) { this.id = id; this.serializer = serializer; this.defaultValue = defaultValue; + this.entityDataAccessor = FastNMS.INSTANCE.constructor$EntityDataAccessor(id, serializer); } @Override @@ -25,4 +29,9 @@ public class SimpleEntityData implements EntityData { public T defaultValue() { return defaultValue; } + + @Override + public Object entityDataAccessor() { + return entityDataAccessor; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java index 7002c5216..78a776bb0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java @@ -32,7 +32,7 @@ import java.util.*; public class BukkitFurniture implements Furniture { private final Key id; private final CustomFurniture furniture; - private final AnchorType anchorType; + private final CustomFurniture.Placement placement; private FurnitureExtraData extraData; // location private final Location location; @@ -61,7 +61,7 @@ public class BukkitFurniture implements Furniture { this.id = furniture.id(); this.extraData = extraData; this.baseEntityId = baseEntity.getEntityId(); - this.anchorType = extraData.anchorType().orElse(furniture.getAnyPlacement()); + this.location = baseEntity.getLocation(); this.baseEntity = new WeakReference<>(baseEntity); this.furniture = furniture; @@ -70,7 +70,7 @@ public class BukkitFurniture implements Furniture { List mainEntityIds = new IntArrayList(); mainEntityIds.add(this.baseEntityId); - CustomFurniture.Placement placement = furniture.getPlacement(anchorType); + this.placement = furniture.getValidPlacement(extraData.anchorType().orElseGet(furniture::getAnyAnchorType)); // bind external furniture Optional optionalExternal = placement.externalModel(); if (optionalExternal.isPresent()) { @@ -171,7 +171,7 @@ public class BukkitFurniture implements Furniture { @NotNull public Location dropLocation() { - Optional dropOffset = config().getPlacement(this.anchorType).dropOffset(); + Optional dropOffset = this.placement.dropOffset(); if (dropOffset.isEmpty()) { return location(); } @@ -275,7 +275,7 @@ public class BukkitFurniture implements Furniture { @Override public @NotNull AnchorType anchorType() { - return this.anchorType; + return this.placement.anchorType(); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java index 6b5c0097b..55f574ac7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureElement.java @@ -49,7 +49,7 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement { Vector3f offset = conjugated.transform(new Vector3f(position())); packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityId, UUID.randomUUID(), position.x() + offset.x, position.y() + offset.y, position.z() - offset.z, 0, position.xRot(), - MEntityTypes.instance$EntityType$ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0 + MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0 )); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, getCachedValues(dyedColor))); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index 04e74f456..c102a457c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -40,7 +40,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { public static final NamespacedKey FURNITURE_SEAT_VECTOR_3F_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_SEAT_VECTOR_3F_KEY); public static final NamespacedKey FURNITURE_COLLISION = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_COLLISION); public static Class COLLISION_ENTITY_CLASS = Interaction.class; - public static Object NMS_COLLISION_ENTITY_TYPE = MEntityTypes.instance$EntityType$INTERACTION; + public static Object NMS_COLLISION_ENTITY_TYPE = MEntityTypes.INTERACTION; public static ColliderType COLLISION_ENTITY_TYPE = ColliderType.INTERACTION; private static BukkitFurnitureManager instance; private final BukkitCraftEngine plugin; @@ -70,7 +70,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { public BukkitFurniture place(Location location, CustomFurniture furniture, FurnitureExtraData extraData, boolean playSound) { Optional optionalAnchorType = extraData.anchorType(); if (optionalAnchorType.isEmpty() || !furniture.isAllowedPlacement(optionalAnchorType.get())) { - extraData.anchorType(furniture.getAnyPlacement()); + extraData.anchorType(furniture.getAnyAnchorType()); } Entity furnitureEntity = EntityUtils.spawnEntity(location.getWorld(), location, EntityType.ITEM_DISPLAY, entity -> { ItemDisplay display = (ItemDisplay) entity; @@ -92,7 +92,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { @Override public void delayedInit() { COLLISION_ENTITY_CLASS = Config.colliderType() == ColliderType.INTERACTION ? Interaction.class : Boat.class; - NMS_COLLISION_ENTITY_TYPE = Config.colliderType() == ColliderType.INTERACTION ? MEntityTypes.instance$EntityType$INTERACTION : MEntityTypes.instance$EntityType$OAK_BOAT; + NMS_COLLISION_ENTITY_TYPE = Config.colliderType() == ColliderType.INTERACTION ? MEntityTypes.INTERACTION : MEntityTypes.OAK_BOAT; COLLISION_ENTITY_TYPE = Config.colliderType(); Bukkit.getPluginManager().registerEvents(this.dismountListener, this.plugin.javaPlugin()); Bukkit.getPluginManager().registerEvents(this.furnitureEventListener, this.plugin.javaPlugin()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java index 9cb6ab155..1ab038efe 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/InteractionHitBox.java @@ -62,7 +62,7 @@ public class InteractionHitBox extends AbstractHitBox { float yaw = position.xRot(); packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityId[0], UUID.randomUUID(), x + offset.x, y + offset.y, z - offset.z, 0, yaw, - MEntityTypes.instance$EntityType$INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 + MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId[0], List.copyOf(this.cachedValues)), true); if (canUseItemOn()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java index 18928102a..fdf1db0c3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java @@ -61,7 +61,7 @@ public class ShulkerHitBox extends AbstractHitBox { if (interactionEntity) { packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityIds[2], UUID.randomUUID(), x + offset.x, y + offset.y - 0.005f, z - offset.z, 0, yaw, - MEntityTypes.instance$EntityType$INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 + MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true); if (canUseOn) { @@ -80,7 +80,7 @@ public class ShulkerHitBox extends AbstractHitBox { if (interactionEntity) { packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityIds[2], UUID.randomUUID(), x + offset.x, y + offset.y - 0.005f - shulkerHeight + scale, z - offset.z, 0, yaw, - MEntityTypes.instance$EntityType$INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 + MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true); if (canUseOn) { @@ -102,14 +102,14 @@ public class ShulkerHitBox extends AbstractHitBox { // first interaction packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityIds[2], UUID.randomUUID(), x + offset.x, y + offset.y - 0.005f, z - offset.z, 0, yaw, - MEntityTypes.instance$EntityType$INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 + MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[2], List.copyOf(cachedInteractionValues)), true); // second interaction double distance = shulkerHeight - scale; packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityIds[3], UUID.randomUUID(), x + offset.x + shulkerDirection.stepX() * distance, y + offset.y - 0.005f, z - offset.z + shulkerDirection.stepZ() * distance, 0, yaw, - MEntityTypes.instance$EntityType$INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 + MEntityTypes.INTERACTION, 0, CoreReflections.instance$Vec3$Zero, 0 ), true); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[3], List.copyOf(cachedInteractionValues)), true); if (canUseOn) { @@ -213,11 +213,11 @@ public class ShulkerHitBox extends AbstractHitBox { double processedY = (fractionalPart >= 0.5) ? integerPart + 1 : originalY; packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityIds[0], UUID.randomUUID(), x + offset.x, originalY, z - offset.z, 0, yaw, - MEntityTypes.instance$EntityType$ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0 + MEntityTypes.ITEM_DISPLAY, 0, CoreReflections.instance$Vec3$Zero, 0 ), false); packets.accept(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket( entityIds[1], UUID.randomUUID(), x + offset.x, processedY, z - offset.z, 0, yaw, - MEntityTypes.instance$EntityType$SHULKER, 0, CoreReflections.instance$Vec3$Zero, 0 + MEntityTypes.SHULKER, 0, CoreReflections.instance$Vec3$Zero, 0 ), false); packets.accept(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityIds[1], List.copyOf(this.cachedShulkerValues)), false); // add passengers diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitCustomProjectile.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitCustomProjectile.java index 45c4193bd..a75f4ee63 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitCustomProjectile.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitCustomProjectile.java @@ -11,4 +11,9 @@ public class BukkitCustomProjectile extends AbstractCustomProjectile { public BukkitCustomProjectile(ProjectileMeta meta, Projectile projectile, Item projectileItem) { super(meta, new BukkitProjectile(projectile), projectileItem); } + + @Override + public BukkitProjectile projectile() { + return (BukkitProjectile) super.projectile(); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java index b86c2324d..a36e23b0e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/projectile/BukkitProjectileManager.java @@ -38,11 +38,11 @@ import java.util.concurrent.ConcurrentHashMap; public class BukkitProjectileManager implements Listener, ProjectileManager { private static BukkitProjectileManager instance; private final BukkitCraftEngine plugin; - private final Map projectiles; + // 会被netty线程访问 + private final Map projectiles = new ConcurrentHashMap<>(); public BukkitProjectileManager(BukkitCraftEngine plugin) { this.plugin = plugin; - this.projectiles = new ConcurrentHashMap<>(); instance = this; } @@ -114,7 +114,8 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { wrapped.getCustomItem().ifPresent(it -> { ProjectileMeta meta = it.settings().projectileMeta(); if (meta != null) { - this.projectiles.put(projectile.getEntityId(), new BukkitCustomProjectile(meta, projectile, wrapped)); + BukkitCustomProjectile customProjectile = new BukkitCustomProjectile(meta, projectile, wrapped); + this.projectiles.put(projectile.getEntityId(), customProjectile); new ProjectileInjectTask(projectile); } }); @@ -161,7 +162,8 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { public class ProjectileInjectTask implements Runnable { private final Projectile projectile; private final SchedulerTask task; - private boolean injected; + private Object cachedServerEntity; + private int lastInjectedInterval = 0; public ProjectileInjectTask(Projectile projectile) { this.projectile = projectile; @@ -178,32 +180,42 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { this.task.cancel(); return; } + Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(this.projectile); - if (!this.injected) { + // 获取server entity + if (this.cachedServerEntity == null) { Object trackedEntity = FastNMS.INSTANCE.field$Entity$trackedEntity(nmsEntity); - if (trackedEntity == null) { - return; - } - Object serverEntity = FastNMS.INSTANCE.filed$ChunkMap$TrackedEntity$serverEntity(trackedEntity); - if (serverEntity == null) { - return; - } - try { - CoreReflections.field$ServerEntity$updateInterval.set(serverEntity, 1); - this.injected = true; - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to update server entity tracking interval", e); - } + if (trackedEntity == null) return; + Object serverEntity = FastNMS.INSTANCE.field$ChunkMap$TrackedEntity$serverEntity(trackedEntity); + if (serverEntity == null) return; + this.cachedServerEntity = serverEntity; } - if (canSpawnParticle(nmsEntity)) { + + boolean inGround = FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity); + if (canSpawnParticle(nmsEntity, inGround)) { this.projectile.getWorld().spawnParticle(ParticleUtils.BUBBLE, this.projectile.getLocation(), 3, 0.1, 0.1, 0.1, 0); } + if (inGround) { + updateProjectileUpdateInterval(Integer.MAX_VALUE); + } else { + updateProjectileUpdateInterval(1); + } } - private static boolean canSpawnParticle(Object nmsEntity) { + private void updateProjectileUpdateInterval(int updateInterval) { + if (this.lastInjectedInterval == updateInterval) return; + try { + CoreReflections.methodHandle$ServerEntity$updateIntervalSetter.invokeExact(this.cachedServerEntity, updateInterval); + this.lastInjectedInterval = updateInterval; + } catch (Throwable e) { + BukkitProjectileManager.this.plugin.logger().warn("Failed to update server entity update interval for " + this.projectile.getType().getKey() + "[" + this.projectile.getUniqueId() + "]", e); + } + } + + private static boolean canSpawnParticle(Object nmsEntity, boolean inGround) { if (!FastNMS.INSTANCE.field$Entity$wasTouchingWater(nmsEntity)) return false; if (CoreReflections.clazz$AbstractArrow.isInstance(nmsEntity)) { - return !FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity); + return !inGround; } return true; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index 241646d22..7586e1919 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.bukkit.item; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; @@ -10,7 +10,6 @@ import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; -import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; @@ -19,22 +18,23 @@ import java.util.List; import java.util.Map; public class BukkitCustomItem extends AbstractCustomItem { - private final Material material; + private final Object item; + private final Object clientItem; - public BukkitCustomItem(Holder id, Key materialKey, Material material, + public BukkitCustomItem(Holder id, Object item, Object clientItem, Key materialKey, Key clientBoundMaterialKey, List behaviors, List> modifiers, List> clientBoundModifiers, ItemSettings settings, Map>> events) { - super(id, materialKey, behaviors, modifiers, clientBoundModifiers, settings, events); - this.material = material; + super(id, materialKey, clientBoundMaterialKey, behaviors, modifiers, clientBoundModifiers, settings, events); + this.item = item; + this.clientItem = clientItem; } @Override public ItemStack buildItemStack(ItemBuildContext context, int count) { - ItemStack item = new ItemStack(this.material); + ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.constructor$ItemStack(this.item, count)); Item wrapped = BukkitCraftEngine.instance().itemManager().wrap(item); - wrapped.count(count); for (ItemDataModifier modifier : this.modifiers) { modifier.apply(wrapped, context); } @@ -43,7 +43,7 @@ public class BukkitCustomItem extends AbstractCustomItem { @Override public Item buildItem(ItemBuildContext context) { - ItemStack item = new ItemStack(this.material); + ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.constructor$ItemStack(this.item, 1)); Item wrapped = BukkitCraftEngine.instance().itemManager().wrap(item); for (ItemDataModifier modifier : dataModifiers()) { modifier.apply(wrapped, context); @@ -51,23 +51,33 @@ public class BukkitCustomItem extends AbstractCustomItem { return BukkitCraftEngine.instance().itemManager().wrap(wrapped.load()); } - public static Builder builder(Material material) { - return new BuilderImpl(material); + public Object clientItem() { + return clientItem; + } + + public Object item() { + return item; + } + + public static Builder builder(Object item, Object clientBoundItem) { + return new BuilderImpl(item, clientBoundItem); } public static class BuilderImpl implements Builder { private Holder id; - private Key materialKey; - private final Material material; + private Key itemKey; + private final Object item; + private Key clientBoundItemKey; + private final Object clientBoundItem; private final Map>> events = new EnumMap<>(EventTrigger.class); private final List behaviors = new ArrayList<>(4); private final List> modifiers = new ArrayList<>(4); private final List> clientBoundModifiers = new ArrayList<>(4); private ItemSettings settings; - public BuilderImpl(Material material) { - this.material = material; - this.materialKey = KeyUtils.namespacedKey2Key(material.getKey()); + public BuilderImpl(Object item, Object clientBoundItem) { + this.item = item; + this.clientBoundItem = clientBoundItem; } @Override @@ -76,9 +86,15 @@ public class BukkitCustomItem extends AbstractCustomItem { return this; } + @Override + public Builder clientBoundMaterial(Key clientBoundMaterial) { + this.clientBoundItemKey = clientBoundMaterial; + return this; + } + @Override public Builder material(Key material) { - this.materialKey = material; + this.itemKey = material; return this; } @@ -133,7 +149,7 @@ public class BukkitCustomItem extends AbstractCustomItem { @Override public CustomItem build() { this.modifiers.addAll(this.settings.modifiers()); - return new BukkitCustomItem(this.id, this.materialKey, this.material, List.copyOf(this.behaviors), + return new BukkitCustomItem(this.id, this.item, this.clientBoundItem, this.itemKey, this.clientBoundItemKey, List.copyOf(this.behaviors), List.copyOf(this.modifiers), List.copyOf(this.clientBoundModifiers), this.settings, this.events); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 632869c87..a74547ea7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item; import com.saicone.rtag.item.ItemTagStream; import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior; +import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior; import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory; import net.momirealms.craftengine.bukkit.item.listener.ArmorEventListener; @@ -12,6 +13,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps; import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.entity.player.Player; @@ -43,6 +45,7 @@ public class BukkitItemManager extends AbstractItemManager { static { registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKETS); registerVanillaItemExtraBehavior(BucketItemBehavior.INSTANCE, ItemKeys.BUCKET); + registerVanillaItemExtraBehavior(FlintAndSteelItemBehavior.INSTANCE, ItemKeys.FLINT_AND_STEEL); } private static BukkitItemManager instance; @@ -198,9 +201,19 @@ public class BukkitItemManager extends AbstractItemManager { } @Override - protected CustomItem.Builder createPlatformItemBuilder(Holder id, Key materialId) { - Material material = ResourceConfigUtils.requireNonNullOrThrow(Registry.MATERIAL.get(KeyUtils.toNamespacedKey(materialId)), () -> new LocalizedResourceConfigException("warning.config.item.invalid_material", materialId.toString())); - return BukkitCustomItem.builder(material).material(materialId).id(id); + protected CustomItem.Builder createPlatformItemBuilder(Holder id, Key materialId, Key clientBoundMaterialId) { + Object item = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(materialId)); + Object clientBoundItem = materialId == clientBoundMaterialId ? item : FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(clientBoundMaterialId)); + if (item == null) { + throw new LocalizedResourceConfigException("warning.config.item.invalid_material", materialId.toString()); + } + if (clientBoundItem == null) { + throw new LocalizedResourceConfigException("warning.config.item.invalid_material", clientBoundMaterialId.toString()); + } + return BukkitCustomItem.builder(item, clientBoundItem) + .id(id) + .material(materialId) + .clientBoundMaterial(clientBoundMaterialId); } @SuppressWarnings("unchecked") @@ -214,7 +227,7 @@ public class BukkitItemManager extends AbstractItemManager { .orElseGet(() -> ((WritableRegistry) BuiltInRegistries.OPTIMIZED_ITEM_ID) .register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), id), id)); Object resourceLocation = KeyUtils.toResourceLocation(id.namespace(), id.value()); - Object mcHolder = ((Optional) CoreReflections.method$Registry$getHolder1.invoke(MBuiltInRegistries.ITEM, CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.instance$Registries$ITEM, resourceLocation))).get(); + Object mcHolder = ((Optional) CoreReflections.method$Registry$getHolder1.invoke(MBuiltInRegistries.ITEM, CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.ITEM, resourceLocation))).get(); Set tags = (Set) CoreReflections.field$Holder$Reference$tags.get(mcHolder); for (Object tag : tags) { Key tagId = Key.of(CoreReflections.field$TagKey$location.get(tag).toString()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java index 892b88c35..7e87edf34 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ComponentItemWrapper.java @@ -111,6 +111,9 @@ public class ComponentItemWrapper implements ItemWrapper { private void setComponentInternal(Object type, DynamicOps ops, Object value) { if (value == null) return; Object componentType = ensureDataComponentType(type); + if (componentType == null) { + return; + } Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType); try { DataResult result = codec.parse(ops, value); @@ -162,4 +165,9 @@ public class ComponentItemWrapper implements ItemWrapper { public void count(int amount) { this.item.setAmount(Math.max(amount, 0)); } + + @Override + public void shrink(int amount) { + count(count() - amount); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java index 3bb4d5932..4615433fc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyItemWrapper.java @@ -8,18 +8,9 @@ import org.bukkit.inventory.ItemStack; public class LegacyItemWrapper implements ItemWrapper { private final RtagItem rtagItem; - private int count; - public LegacyItemWrapper(RtagItem rtagItem, int count) { + public LegacyItemWrapper(RtagItem rtagItem) { this.rtagItem = rtagItem; - this.count = count; - } - - @Override - public ItemStack getItem() { - ItemStack itemStack = this.rtagItem.getItem(); - itemStack.setAmount(this.count); - return itemStack; } public boolean setTag(Object value, Object... path) { @@ -49,12 +40,12 @@ public class LegacyItemWrapper implements ItemWrapper { } public int count() { - return this.count; + return getItem().getAmount(); } public void count(int amount) { if (amount < 0) amount = 0; - this.count = amount; + getItem().setAmount(amount); } public Object getExactTag(Object... path) { @@ -75,9 +66,12 @@ public class LegacyItemWrapper implements ItemWrapper { @Override public ItemStack load() { - ItemStack itemStack = this.rtagItem.load(); - itemStack.setAmount(Math.max(this.count, 0)); - return itemStack; + return this.rtagItem.load(); + } + + @Override + public ItemStack getItem() { + return this.rtagItem.getItem(); } @Override @@ -87,6 +81,13 @@ public class LegacyItemWrapper implements ItemWrapper { @Override public ItemWrapper copyWithCount(int count) { - return new LegacyItemWrapper(new RtagItem(this.rtagItem.loadCopy()), count); + ItemStack copied = this.rtagItem.loadCopy(); + copied.setAmount(count); + return new LegacyItemWrapper(new RtagItem(copied)); + } + + @Override + public void shrink(int amount) { + this.count(count() - amount); } } \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java index c325fcb4c..9a2050efe 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/LegacyNetworkItemHandler.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.item; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; @@ -25,11 +26,25 @@ import java.util.Map; import java.util.Optional; import java.util.function.BiConsumer; +@SuppressWarnings("DuplicatedCode") public class LegacyNetworkItemHandler implements NetworkItemHandler { @Override public Optional> c2s(Item wrapped) { - if (!wrapped.hasTag(NETWORK_ITEM_TAG)) return Optional.empty(); + Optional> optionalCustomItem = wrapped.getCustomItem(); + boolean hasDifferentMaterial = false; + if (optionalCustomItem.isPresent()) { + BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get(); + if (customItem.item() != FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject())) { + wrapped = wrapped.unsafeTransmuteCopy(customItem.item(), wrapped.count()); + hasDifferentMaterial = true; + } + } + if (!wrapped.hasTag(NETWORK_ITEM_TAG)) { + if (hasDifferentMaterial) { + return Optional.of(wrapped); + } + } CompoundTag networkData = (CompoundTag) wrapped.getNBTTag(NETWORK_ITEM_TAG); if (networkData == null) return Optional.empty(); wrapped.removeTag(NETWORK_ITEM_TAG); @@ -46,12 +61,16 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler { Optional> optionalCustomItem = wrapped.getCustomItem(); if (optionalCustomItem.isEmpty()) { if (!Config.interceptItem()) return Optional.empty(); - return new OtherItem(wrapped).process(); + return new OtherItem(wrapped, false).process(); } else { - CustomItem customItem = optionalCustomItem.get(); + BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get(); + boolean hasDifferentMaterial = FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject()) != customItem.clientItem(); + if (hasDifferentMaterial) { + wrapped = wrapped.unsafeTransmuteCopy(customItem.clientItem(), wrapped.count()); + } if (!customItem.hasClientBoundDataModifier()) { - if (!Config.interceptItem()) return Optional.empty(); - return new OtherItem(wrapped).process(); + if (!Config.interceptItem() && !hasDifferentMaterial) return Optional.empty(); + return new OtherItem(wrapped, hasDifferentMaterial).process(); } else { CompoundTag tag = new CompoundTag(); Tag argumentTag = wrapped.getNBTTag(ArgumentModifier.ARGUMENTS_TAG); @@ -77,7 +96,12 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler { processLore(wrapped, tag::put); } } - if (tag.isEmpty()) return Optional.empty(); + if (tag.isEmpty()) { + if (hasDifferentMaterial) { + return Optional.of(wrapped); + } + return Optional.empty(); + } wrapped.setTag(tag, NETWORK_ITEM_TAG); return Optional.of(wrapped); } @@ -130,9 +154,11 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler { private final Item item; private boolean globalChanged = false; private CompoundTag networkTag; + private final boolean forceReturn; - public OtherItem(Item item) { + public OtherItem(Item item, boolean forceReturn) { this.item = item; + this.forceReturn = forceReturn; } public Optional> process() { @@ -145,6 +171,8 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler { if (this.globalChanged) { this.item.setTag(this.networkTag, NETWORK_ITEM_TAG); return Optional.of(this.item); + } else if (this.forceReturn) { + return Optional.of(this.item); } else { return Optional.empty(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java index 353cf9d6f..c584d3de4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/ModernNetworkItemHandler.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.item; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.modifier.ArgumentModifier; @@ -30,8 +31,22 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler> c2s(Item wrapped) { Tag customData = wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA); if (!(customData instanceof CompoundTag compoundTag)) return Optional.empty(); + Optional> optionalCustomItem = wrapped.getCustomItem(); + boolean hasDifferentMaterial = false; + if (optionalCustomItem.isPresent()) { + BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get(); + if (customItem.item() != FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject())) { + wrapped = wrapped.unsafeTransmuteCopy(customItem.item(), wrapped.count()); + hasDifferentMaterial = true; + } + } CompoundTag networkData = compoundTag.getCompound(NETWORK_ITEM_TAG); - if (networkData == null) return Optional.empty(); + if (networkData == null) { + if (hasDifferentMaterial) { + return Optional.of(wrapped); + } + return Optional.empty(); + } compoundTag.remove(NETWORK_ITEM_TAG); for (Map.Entry entry : networkData.entrySet()) { if (entry.getValue() instanceof CompoundTag tag) { @@ -48,12 +63,16 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler> optionalCustomItem = wrapped.getCustomItem(); if (optionalCustomItem.isEmpty()) { if (!Config.interceptItem()) return Optional.empty(); - return new OtherItem(wrapped).process(); + return new OtherItem(wrapped, false).process(); } else { - CustomItem customItem = optionalCustomItem.get(); + BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get(); + boolean hasDifferentMaterial = FastNMS.INSTANCE.method$ItemStack$getItem(wrapped.getLiteralObject()) != customItem.clientItem(); + if (hasDifferentMaterial) { + wrapped = wrapped.unsafeTransmuteCopy(customItem.clientItem(), wrapped.count()); + } if (!customItem.hasClientBoundDataModifier()) { - if (!Config.interceptItem()) return Optional.empty(); - return new OtherItem(wrapped).process(); + if (!Config.interceptItem() && !hasDifferentMaterial) return Optional.empty(); + return new OtherItem(wrapped, hasDifferentMaterial).process(); } else { CompoundTag customData = Optional.ofNullable(wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA)).map(CompoundTag.class::cast).orElse(new CompoundTag()); CompoundTag arguments = customData.getCompound(ArgumentModifier.ARGUMENTS_TAG); @@ -86,7 +105,10 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler tag); } } - if (tag.isEmpty()) return Optional.empty(); + if (tag.isEmpty()) { + if (hasDifferentMaterial) return Optional.of(wrapped); + return Optional.empty(); + } customData.put(NETWORK_ITEM_TAG, tag); wrapped.setNBTComponent(ComponentTypes.CUSTOM_DATA, customData); return Optional.of(wrapped); @@ -203,11 +225,13 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler item; + private final boolean forceReturn; private boolean globalChanged = false; private CompoundTag tag; - public OtherItem(Item item) { + public OtherItem(Item item, boolean forceReturn) { this.item = item; + this.forceReturn = forceReturn; } public Optional> process() { @@ -231,6 +255,8 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler= maxLevel) return InteractionResult.PASS; + boolean willRaise = (currentLevel == 0) && (this.chance > 0) || (RandomUtils.generateRandomDouble(0, 1) < this.chance); + + if (willRaise) { + levelled.setLevel(currentLevel + 1); + EntityChangeBlockEvent event = new EntityChangeBlockEvent((Entity) context.getPlayer().platformPlayer(), block.block(), levelled); + if (EventUtils.fireAndCheckCancel(event)) { + return InteractionResult.FAIL; + } + block.block().setBlockData(levelled); + } + + context.getLevel().levelEvent(WorldEvents.COMPOSTER_COMPOSTS, context.getClickedPos(), willRaise ? 1 : 0); + ((World) context.getLevel().platformWorld()).sendGameEvent((Entity) context.getPlayer().platformPlayer(), GameEvent.BLOCK_CHANGE, new Vector(block.x() + 0.5, block.y() + 0.5, block.z() + 0.5)); + if (currentLevel + 1 == 7) { + FastNMS.INSTANCE.method$LevelAccessor$scheduleTick(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), blockOwner, 20); + } + if (!context.getPlayer().canInstabuild()) { + context.getItem().shrink(1); + } + context.getPlayer().swingHand(context.getHand()); + return InteractionResult.SUCCESS; + } + + public static class Factory implements ItemBehaviorFactory { + @Override + public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { + double chance = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("chance", 0.55), "chance"); + return new CompostableItemBehavior(chance); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java new file mode 100644 index 000000000..9d46867ed --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java @@ -0,0 +1,167 @@ +package net.momirealms.craftengine.bukkit.item.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; +import net.momirealms.craftengine.bukkit.util.InteractUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.sound.SoundSource; +import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.world.BlockPos; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.nio.file.Path; +import java.util.Map; + +public class FlintAndSteelItemBehavior extends ItemBehavior { + public static final FlintAndSteelItemBehavior INSTANCE = new FlintAndSteelItemBehavior(); + public static final Factory FACTORY = new Factory(); + private static final Key FLINT_SOUND = Key.of("item.flintandsteel.use"); + + @SuppressWarnings("unchecked") + @Override + public InteractionResult useOnBlock(UseOnContext context) { + BlockPos clickedPos = context.getClickedPos(); + BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(clickedPos); + Block block = clicked.block(); + BlockPos firePos = clickedPos.relative(context.getClickedFace()); + Direction direction = context.getHorizontalDirection(); + + // 最基础的判断能不能着火,不能着火都是扯蛋 + try { + if (!(boolean) CoreReflections.method$BaseFireBlock$canBePlacedAt.invoke(null, context.getLevel().serverWorld(), LocationUtils.toBlockPos(firePos), DirectionUtils.toNMSDirection(direction))) { + return InteractionResult.PASS; + } + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call BaseFireBlock$canBePlacedAt", e); + return InteractionResult.PASS; + } + + // 判断点击的方块是否可燃 + BlockData clickedBlockData = block.getBlockData(); + Object clickedBlockState = BlockStateUtils.blockDataToBlockState(clickedBlockData); + boolean isClickedBlockBurnable; + try { + isClickedBlockBurnable = BlockStateUtils.isBurnable(clickedBlockState) || + (context.getClickedFace() == Direction.UP && (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( + clickedBlockState, context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL)); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); + return InteractionResult.PASS; + } + + net.momirealms.craftengine.core.entity.player.Player player = context.getPlayer(); + // 点击对象直接可燃,则忽略 + if (isClickedBlockBurnable) { + int stateId = BlockStateUtils.blockStateToId(clickedBlockState); + if (BlockStateUtils.isVanillaBlock(stateId)) { + return InteractionResult.PASS; + } else { + // 点击对象为自定义方块 + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); + // 原版外观也可燃 + if (BlockStateUtils.isBurnable(immutableBlockState.vanillaBlockState().handle())) { + return InteractionResult.PASS; + } + BlockData vanillaBlockState = BlockStateUtils.fromBlockData(immutableBlockState.vanillaBlockState().handle()); + // 点击的是方块上面,则只需要判断shift和可交互 + if (direction == Direction.UP) { + // 客户端层面必须可交互 + if (!InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, + context.getHitResult(), (Item) context.getItem())) { + return InteractionResult.PASS; + } + // 且没有shift + if (!player.isSecondaryUseActive()) { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + } + } else { + // 玩家觉得自定义方块不可燃,且点击了侧面,那么就要判断火源下方的方块是否可燃,如果不可燃,则补发声音 + BlockPos belowFirePos = firePos.relative(Direction.DOWN); + BukkitBlockInWorld belowFireBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(belowFirePos); + boolean belowCanBurn; + try { + Block belowBlock = belowFireBlock.block(); + belowCanBurn = BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(belowBlock.getBlockData())) || + (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( + BlockStateUtils.blockDataToBlockState(belowFireBlock.block().getBlockData()), context.getLevel().serverWorld(), LocationUtils.toBlockPos(belowFirePos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); + return InteractionResult.PASS; + } + + // 客户端觉得这玩意可交互,就会忽略声音 + if (InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, context.getHitResult(), (Item) context.getItem())) { + // 如果按住了shift,则代表尝试对侧面方块点火 + if (player.isSecondaryUseActive()) { + // 如果底部不能燃烧,则燃烧点位为侧面,需要补发 + if (!belowCanBurn) { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); + } + } else { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + } + } else { + // 如果底部方块不可燃烧才补发 + if (!belowCanBurn) { + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); + } + } + } + } + } else { + // 如果点击的方块不可燃烧,但是服务端却认为可以放置火源,则可燃烧的方块一定位于火源的六个方向之一。 + Direction relativeDirection = direction.opposite(); + for (Direction dir : Direction.values()) { + if (dir == relativeDirection) continue; + BlockPos relPos = firePos.relative(dir); + BukkitBlockInWorld nearByBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(relPos); + BlockData nearbyBlockData = nearByBlock.block().getBlockData(); + Object nearbyBlockState = BlockStateUtils.blockDataToBlockState(nearbyBlockData); + int stateID = BlockStateUtils.blockStateToId(nearbyBlockState); + if (BlockStateUtils.isVanillaBlock(stateID)) { + if (BlockStateUtils.isBurnable(nearbyBlockState)) { + return InteractionResult.PASS; + } + try { + if (dir == Direction.DOWN && (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke( + nearbyBlockState, context.getLevel().serverWorld(), LocationUtils.toBlockPos(relPos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL)) { + return InteractionResult.PASS; + } + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e); + return InteractionResult.PASS; + } + } + } + player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.swingHand(context.getHand()); + } + return InteractionResult.PASS; + } + + public static class Factory implements ItemBehaviorFactory { + @Override + public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { + return INSTANCE; + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java index f840d2cb7..2d283d73f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/BukkitItemFactory.java @@ -2,12 +2,13 @@ package net.momirealms.craftengine.bukkit.item.factory; import com.google.gson.JsonElement; import com.saicone.rtag.item.ItemTagStream; +import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.ItemTags; -import net.momirealms.craftengine.core.item.EquipmentData; import net.momirealms.craftengine.core.item.ItemFactory; import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.item.JukeboxPlayable; +import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.Tag; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index f79b48f36..1a3c19dc9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -4,11 +4,16 @@ import com.google.gson.JsonElement; import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper; import net.momirealms.craftengine.bukkit.item.ComponentTypes; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps; import net.momirealms.craftengine.bukkit.util.EnchantmentUtils; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Trim; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; @@ -38,29 +43,136 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory rootMap = (Map) item.getJavaComponent(ComponentTypes.CUSTOM_DATA).orElse(null); + if (rootMap == null) return null; + Object currentObj = rootMap; + for (int i = 0; i < path.length; i++) { + Object pathSegment = path[i]; + if (pathSegment == null) return null; + String key = pathSegment.toString(); + currentObj = ((Map) currentObj).get(key); + if (currentObj == null) return null; + if (i == path.length - 1) { + return currentObj; + } + if (!(currentObj instanceof Map)) { + return null; + } + } + return currentObj; } @Override protected Tag getNBTTag(ComponentItemWrapper item, Object... path) { - throw new UnsupportedOperationException("This feature is not available on 1.20.5+"); + CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(null); + if (rootTag == null) return null; + Tag currentTag = rootTag; + for (int i = 0; i < path.length; i++) { + Object pathSegment = path[i]; + if (pathSegment == null) return null; + CompoundTag t = (CompoundTag) currentTag; + String key = pathSegment.toString(); + currentTag = t.get(key); + if (currentTag == null) return null; + if (i == path.length - 1) { + return currentTag; + } + if (!(currentTag instanceof CompoundTag)) { + return null; + } + } + return currentTag; } @Override protected void setTag(ComponentItemWrapper item, Object value, Object... path) { - throw new UnsupportedOperationException("This feature is not available on 1.20.5+"); + Tag valueTag; + if (value instanceof Tag tag) { + valueTag = tag; + } else if (value instanceof JsonElement je) { + valueTag = MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, je); + } else if (CoreReflections.clazz$Tag.isInstance(value)) { + valueTag = MRegistryOps.NBT.convertTo(MRegistryOps.SPARROW_NBT, value); + } else { + assert MRegistryOps.JAVA != null; + valueTag = MRegistryOps.JAVA.convertTo(MRegistryOps.SPARROW_NBT, value); + } + + CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(new CompoundTag()); + + if (path == null || path.length == 0) { + if (valueTag instanceof CompoundTag) { + rootTag = (CompoundTag) valueTag; + } else { + throw new IllegalArgumentException("Cannot set non-CompoundTag as root without path"); + } + } else { + CompoundTag currentTag = rootTag; + for (int i = 0; i < path.length - 1; i++) { + Object pathSegment = path[i]; + if (pathSegment == null) throw new NullPointerException("Path segment cannot be null"); + + String key = pathSegment.toString(); + Tag nextTag = currentTag.get(key); + + if (!(nextTag instanceof CompoundTag)) { + nextTag = new CompoundTag(); + currentTag.put(key, nextTag); + } + currentTag = (CompoundTag) nextTag; + } + + String finalKey = path[path.length - 1].toString(); + currentTag.put(finalKey, valueTag); + } + + item.setSparrowNBTComponent(ComponentTypes.CUSTOM_DATA, rootTag); } @Override protected boolean hasTag(ComponentItemWrapper item, Object... path) { - throw new UnsupportedOperationException("This feature is not available on 1.20.5+"); + return getNBTTag(item, path) != null; } @Override protected boolean removeTag(ComponentItemWrapper item, Object... path) { - throw new UnsupportedOperationException("This feature is not available on 1.20.5+"); + CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(null); + if (rootTag == null || path == null || path.length == 0) return false; + + if (path.length == 1) { + String key = path[0].toString(); + if (rootTag.containsKey(key)) { + rootTag.remove(key); + item.setSparrowNBTComponent(ComponentTypes.CUSTOM_DATA, rootTag); + return true; + } + return false; + } + + CompoundTag parentTag = rootTag; + for (int i = 0; i < path.length - 1; i++) { + Object pathSegment = path[i]; + if (pathSegment == null) return false; + + String key = pathSegment.toString(); + Tag childTag = parentTag.get(key); + + if (!(childTag instanceof CompoundTag)) { + return false; + } + parentTag = (CompoundTag) childTag; + } + + String finalKey = path[path.length - 1].toString(); + if (parentTag.containsKey(finalKey)) { + parentTag.remove(finalKey); + item.setSparrowNBTComponent(ComponentTypes.CUSTOM_DATA, rootTag); + return true; + } + return false; } @Override @@ -397,9 +509,9 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory { @Override protected LegacyItemWrapper wrapInternal(ItemStack item) { - return new LegacyItemWrapper(new RtagItem(item), item.getAmount()); + return new LegacyItemWrapper(new RtagItem(item)); } @Override @@ -305,18 +308,32 @@ public class UniversalItemFactory extends BukkitItemFactory { @Override protected LegacyItemWrapper mergeCopy(LegacyItemWrapper item1, LegacyItemWrapper item2) { Object itemStack = ItemObject.copy(item2.getLiteralObject()); - ItemObject.setCustomDataTag(itemStack, TagCompound.clone(ItemObject.getCustomDataTag(item1.getLiteralObject()))); + FastNMS.INSTANCE.method$ItemStack$setTag(itemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item1.getLiteralObject()))); // one more step than vanilla - TagCompound.merge(ItemObject.getCustomDataTag(itemStack), ItemObject.getCustomDataTag(item2.getLiteralObject()), true, true); - return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(itemStack)), item2.count()); + TagCompound.merge(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(itemStack), FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item2.getLiteralObject()), true, true); + return new LegacyItemWrapper(new RtagItem(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(itemStack))); } @Override protected void merge(LegacyItemWrapper item1, LegacyItemWrapper item2) { // load previous changes on nms items item1.load(); - TagCompound.merge(ItemObject.getCustomDataTag(item1.getLiteralObject()), ItemObject.getCustomDataTag(item2.getLiteralObject()), true, true); + TagCompound.merge(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item1.getLiteralObject()), FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item2.getLiteralObject()), true, true); // update wrapped item item1.update(); } + + @Override + protected LegacyItemWrapper transmuteCopy(LegacyItemWrapper item, Key newItem, int amount) { + Object newItemStack = FastNMS.INSTANCE.constructor$ItemStack(FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(newItem)), amount); + FastNMS.INSTANCE.method$ItemStack$setTag(newItemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item.getLiteralObject()))); + return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(newItemStack))); + } + + @Override + protected LegacyItemWrapper unsafeTransmuteCopy(LegacyItemWrapper item, Object newItem, int amount) { + Object newItemStack = FastNMS.INSTANCE.constructor$ItemStack(newItem, amount); + FastNMS.INSTANCE.method$ItemStack$setTag(newItemStack, TagCompound.clone(FastNMS.INSTANCE.field$ItemStack$getOrCreateTag(item.getLiteralObject()))); + return new LegacyItemWrapper(new RtagItem(ItemObject.asCraftMirror(newItemStack))); + } } \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java index 2c6e0cf6f..de86d8189 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/DebugStickListener.java @@ -73,7 +73,7 @@ public class DebugStickListener implements Listener { ComponentUtils.adventureToMinecraft(Component.translatable("item.minecraft.debug_stick.empty").arguments(Component.text(blockId))), true); player.sendPacket(systemChatPacket, false); } else { - LegacyItemWrapper wrapped = new LegacyItemWrapper(new RtagItem(itemInHand), itemInHand.getAmount()); + LegacyItemWrapper wrapped = new LegacyItemWrapper(new RtagItem(itemInHand)); Object storedData = wrapped.getJavaTag("craftengine:debug_stick_state"); if (storedData == null) storedData = new HashMap<>(); if (storedData instanceof Map map) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index e67c1239c..7be490882 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -15,12 +15,12 @@ import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.item.setting.FoodData; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.util.Cancellable; -import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; @@ -28,11 +28,16 @@ import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.inventory.EquipmentSlot; @@ -49,6 +54,28 @@ public class ItemEventListener implements Listener { this.plugin = plugin; } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onInteractEntity(PlayerInteractEntityEvent event) { + BukkitServerPlayer serverPlayer = this.plugin.adapt(event.getPlayer()); + if (serverPlayer == null) return; + InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + Item itemInHand = serverPlayer.getItemInHand(hand); + + if (itemInHand == null) return; + Optional> optionalCustomItem = itemInHand.getCustomItem(); + if (optionalCustomItem.isEmpty()) return; + + Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(event.getRightClicked().getLocation())) + .withParameter(DirectContextParameters.HAND, hand) + ); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.RIGHT_CLICK); + } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onInteractBlock(PlayerInteractEvent event) { Action action = event.getAction(); @@ -62,6 +89,7 @@ public class ItemEventListener implements Listener { } BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + if (serverPlayer == null) return; InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; // 如果本tick内主手已被处理,则不处理副手 // 这是因为客户端可能会同时发主副手交互包,但实际上只能处理其中一个 @@ -318,18 +346,47 @@ public class ItemEventListener implements Listener { if (optionalCustomItem.isEmpty()) { return; } - Cancellable dummy = Cancellable.dummy(); + Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); CustomItem customItem = optionalCustomItem.get(); PlayerOptionalContext context = PlayerOptionalContext.of(this.plugin.adapt(event.getPlayer()), ContextHolder.builder() .withParameter(DirectContextParameters.ITEM_IN_HAND, wrapped) - .withParameter(DirectContextParameters.EVENT, dummy) + .withParameter(DirectContextParameters.EVENT, cancellable) .withParameter(DirectContextParameters.HAND, event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND) ); customItem.execute(context, EventTrigger.CONSUME); - if (dummy.isCancelled()) { - event.setCancelled(true); + if (event.isCancelled()) { return; } + if (event.getPlayer().getGameMode() != GameMode.CREATIVE) { + Key replacement = customItem.settings().consumeReplacement(); + if (replacement == null) { + event.setReplacement(null); + } else { + ItemStack replacementItem = this.plugin.itemManager().buildItemStack(replacement, this.plugin.adapt(event.getPlayer())); + event.setReplacement(replacementItem); + } + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) + public void onFoodLevelChange(FoodLevelChangeEvent event) { + if (VersionHelper.isOrAbove1_20_5()) return; + if (!(event.getEntity() instanceof Player player)) return; + ItemStack consumedItem = event.getItem(); + if (ItemUtils.isEmpty(consumedItem)) return; + Item wrapped = this.plugin.itemManager().wrap(consumedItem); + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isEmpty()) { + return; + } + CustomItem customItem = optionalCustomItem.get(); + FoodData foodData = customItem.settings().foodData(); + if (foodData == null) return; + event.setCancelled(true); + int oldFoodLevel = player.getFoodLevel(); + if (foodData.nutrition() != 0) player.setFoodLevel(MCUtils.clamp(oldFoodLevel + foodData.nutrition(), 0, 20)); + float oldSaturation = player.getSaturation(); + if (foodData.saturation() != 0) player.setSaturation(MCUtils.clamp(oldSaturation, 0, 10)); } private boolean cancelEventIfHasInteraction(PlayerInteractEvent event, BukkitServerPlayer player, InteractionHand hand) { @@ -344,4 +401,17 @@ public class ItemEventListener implements Listener { } return false; } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) + public void onEntityDamage(EntityDamageEvent event) { + if (event.getEntityType() == EntityType.ITEM && event.getEntity() instanceof org.bukkit.entity.Item item) { + Optional.ofNullable(this.plugin.itemManager().wrap(item.getItemStack())) + .flatMap(Item::getCustomItem) + .ifPresent(it -> { + if (it.settings().invulnerable().contains(DamageCauseUtils.fromBukkit(event.getCause()))) { + event.setCancelled(true); + } + }); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 05b6873eb..f37e0118c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.MaterialUtils; import net.momirealms.craftengine.bukkit.util.RecipeUtils; @@ -45,9 +46,9 @@ public class BukkitRecipeManager extends AbstractRecipeManager { // 将自定义配方转为“广义”配方,接受更加宽容的输入 // 部分过程借助bukkit完成,部分直接通过nms方法注册 private static final Map>> MIXED_RECIPE_CONVERTORS = new HashMap<>(); - private static Object nmsRecipeManager; private static final List injectedIngredients = new ArrayList<>(); - private static final IdentityHashMap, Object> recipeToMcRecipeHolder = new IdentityHashMap<>(); + private static final IdentityHashMap, Object> CE_RECIPE_2_NMS_HOLDER = new IdentityHashMap<>(); + private static Object nmsRecipeManager; private static void registerNMSSmithingRecipe(Object recipe) { try { @@ -265,7 +266,8 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } public Object nmsRecipeHolderByRecipe(Recipe recipe) { - return recipeToMcRecipeHolder.get(recipe); + if (super.isReloading) return null; + return CE_RECIPE_2_NMS_HOLDER.get(recipe); } public static Object nmsRecipeManager() { @@ -287,6 +289,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { @Override public void load() { if (!Config.enableRecipeSystem()) return; + super.isReloading = true; if (VersionHelper.isOrAbove1_21_2()) { try { this.stolenFeatureFlagSet = CoreReflections.field$RecipeManager$featureflagset.get(nmsRecipeManager); @@ -308,7 +311,6 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } catch (ReflectiveOperationException e) { this.plugin.logger().warn("Failed to unregister recipes", e); } - recipeToMcRecipeHolder.clear(); } @Override @@ -320,6 +322,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { @Override public void disable() { unload(); + CE_RECIPE_2_NMS_HOLDER.clear(); HandlerList.unregisterAll(this.recipeEventListener); if (this.crafterEventListener != null) { HandlerList.unregisterAll(this.crafterEventListener); @@ -473,6 +476,15 @@ public class BukkitRecipeManager extends AbstractRecipeManager { // clear cache injectedIngredients.clear(); + + CE_RECIPE_2_NMS_HOLDER.clear(); + // create mappings + for (Map.Entry> entry : this.byId.entrySet()) { + Optional nmsRecipe = getOptionalNMSRecipe(entry.getKey()); + nmsRecipe.ifPresent(o -> CE_RECIPE_2_NMS_HOLDER.put(entry.getValue(), o)); + } + + super.isReloading = false; } catch (Exception e) { this.plugin.logger().warn("Failed to run delayed recipe tasks", e); } @@ -691,7 +703,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { return optionalItem.map(itemStackCustomItem -> MaterialUtils.getMaterial(itemStackCustomItem.material())).orElse(null); } - private static List getIngredientLooks(List> holders) throws ReflectiveOperationException { + private static List getIngredientLooks(List> holders) { List itemStacks = new ArrayList<>(); for (Holder holder : holders) { ItemStack itemStack = BukkitItemManager.instance().getBuildableItem(holder.value()).get().buildItemStack(ItemBuildContext.EMPTY, 1); @@ -710,8 +722,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { .map(Optional::get) .toList(); - Object shapedRecipe = getNMSRecipe(id); - recipeToMcRecipeHolder.put(recipe, shapedRecipe); + Object shapedRecipe = getOptionalNMSRecipe(id).get(); if (VersionHelper.isOrAbove1_20_2()) { shapedRecipe = CoreReflections.field$RecipeHolder$recipe.get(shapedRecipe); } @@ -731,8 +742,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { try { List> actualIngredients = recipe.ingredientsInUse(); - Object shapelessRecipe = getNMSRecipe(id); - recipeToMcRecipeHolder.put(recipe, shapelessRecipe); + Object shapelessRecipe = getOptionalNMSRecipe(id).get(); if (VersionHelper.isOrAbove1_20_2()) { shapelessRecipe = CoreReflections.field$RecipeHolder$recipe.get(shapelessRecipe); } @@ -751,8 +761,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { private static void injectCookingRecipe(Key id, CustomCookingRecipe recipe) { try { Ingredient actualIngredient = recipe.ingredient(); - Object smeltingRecipe = getNMSRecipe(id); - recipeToMcRecipeHolder.put(recipe, smeltingRecipe); + Object smeltingRecipe = getOptionalNMSRecipe(id).get(); if (VersionHelper.isOrAbove1_20_2()) { smeltingRecipe = CoreReflections.field$RecipeHolder$recipe.get(smeltingRecipe); } @@ -771,23 +780,17 @@ public class BukkitRecipeManager extends AbstractRecipeManager { // 获取nms配方,请注意1.20.1获取配方本身,而1.20.2+获取的是配方的holder // recipe on 1.20.1 and holder on 1.20.2+ - private static Object getNMSRecipe(Key id) throws ReflectiveOperationException { + private static Optional getOptionalNMSRecipe(Key id) throws ReflectiveOperationException { if (VersionHelper.isOrAbove1_21_2()) { - Object resourceKey = CraftBukkitReflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())); + Object resourceKey = FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.RECIPE, KeyUtils.toResourceLocation(id)); @SuppressWarnings("unchecked") Optional optional = (Optional) CoreReflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceKey); - if (optional.isEmpty()) { - throw new IllegalArgumentException("Recipe " + id + " not found"); - } - return optional.get(); + return optional; } else { Object resourceLocation = KeyUtils.toResourceLocation(id); @SuppressWarnings("unchecked") Optional optional = (Optional) CoreReflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceLocation); - if (optional.isEmpty()) { - throw new IllegalArgumentException("Recipe " + id + " not found"); - } - return optional.get(); + return optional; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 3e059ee13..a2bc98eee 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -20,6 +20,7 @@ import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; +import net.momirealms.craftengine.core.item.setting.AnvilRepairItem; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -32,6 +33,7 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Campfire; import org.bukkit.block.Furnace; +import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -789,6 +791,49 @@ public class RecipeEventListener implements Listener { return new Pair<>(first, second); } + // 不是完美的解决方案,仍然需要更多的探讨 + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onCraft(CraftItemEvent event) { + org.bukkit.inventory.Recipe recipe = event.getRecipe(); + if (!(recipe instanceof ShapelessRecipe) && !(recipe instanceof ShapedRecipe)) return; + HumanEntity humanEntity = event.getWhoClicked(); + if (!(humanEntity instanceof Player player)) return; + CraftingInventory inventory = event.getInventory(); + ItemStack result = inventory.getResult(); + if (result == null) return; + ItemStack[] usedItems = inventory.getMatrix(); + ItemStack[] replacements = new ItemStack[usedItems.length]; + boolean hasReplacement = false; + for (int i = 0; i < usedItems.length; i++) { + ItemStack usedItem = usedItems[i]; + if (ItemUtils.isEmpty(usedItem)) continue; + if (usedItem.getAmount() != 1) continue; + Item wrapped = BukkitItemManager.instance().wrap(usedItem); + if (wrapped == null) continue; + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + Key remainingItem = customItem.settings().craftRemainder(); + if (remainingItem != null) { + replacements[i] = BukkitItemManager.instance().buildItemStack(remainingItem, this.plugin.adapt(player)); + hasReplacement = true; + } + } + } + if (!hasReplacement) return; + Runnable delayedTask = () -> { + for (int i = 0; i < replacements.length; i++) { + if (replacements[i] == null) continue; + inventory.setItem(i + 1, replacements[i]); + } + }; + if (VersionHelper.isFolia()) { + player.getScheduler().run(this.plugin.javaPlugin(), (t) -> delayedTask.run(), () -> {}); + } else { + this.plugin.scheduler().sync().runDelayed(delayedTask); + } + } + @EventHandler(ignoreCancelled = true) public void onCraftingRecipe(PrepareItemCraftEvent event) { if (!Config.enableRecipeSystem()) return; @@ -843,7 +888,7 @@ public class RecipeEventListener implements Listener { try { player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView()); } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to get inventory viewer", e); + this.plugin.logger().warn("Failed to get inventory viewer", e); return; } @@ -854,14 +899,18 @@ public class RecipeEventListener implements Listener { if (ceRecipe != null) { inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); serverPlayer.setLastUsedRecipe(ceRecipe.id()); - correctCraftingRecipeUsed(inventory, ceRecipe); + if (!ceRecipe.id().equals(recipeId)) { + correctCraftingRecipeUsed(inventory, ceRecipe); + } return; } ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input, lastRecipe); if (ceRecipe != null) { inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); serverPlayer.setLastUsedRecipe(ceRecipe.id()); - correctCraftingRecipeUsed(inventory, ceRecipe); + if (!ceRecipe.id().equals(recipeId)) { + correctCraftingRecipeUsed(inventory, ceRecipe); + } return; } // clear result if not met @@ -869,9 +918,8 @@ public class RecipeEventListener implements Listener { } private void correctCraftingRecipeUsed(CraftingInventory inventory, Recipe recipe) { - Object holderOrRecipe = recipeManager.nmsRecipeHolderByRecipe(recipe); + Object holderOrRecipe = this.recipeManager.nmsRecipeHolderByRecipe(recipe); if (holderOrRecipe == null) { - // it's a vanilla recipe but not injected return; } try { @@ -922,20 +970,21 @@ public class RecipeEventListener implements Listener { CustomSmithingTransformRecipe transformRecipe = (CustomSmithingTransformRecipe) ceRecipe; ItemStack processed = transformRecipe.assemble(new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY), this.itemManager.wrap(base)); event.setResult(processed); - correctSmithingRecipeUsed(inventory, ceRecipe); + if (!ceRecipe.id().equals(recipeId)) { + correctSmithingRecipeUsed(inventory, ceRecipe); + } } private void correctSmithingRecipeUsed(SmithingInventory inventory, Recipe recipe) { - Object holderOrRecipe = recipeManager.nmsRecipeHolderByRecipe(recipe); + Object holderOrRecipe = this.recipeManager.nmsRecipeHolderByRecipe(recipe); if (holderOrRecipe == null) { - // it's a vanilla recipe but not injected return; } try { Object resultInventory = CraftBukkitReflections.field$CraftResultInventory$resultInventory.get(inventory); CoreReflections.field$ResultContainer$recipeUsed.set(resultInventory, holderOrRecipe); } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to correct used recipe", e); + this.plugin.logger().warn("Failed to correct used recipe", e); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index b441b5ba1..d00647089 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -53,7 +53,6 @@ import org.bukkit.plugin.java.JavaPlugin; import org.jspecify.annotations.Nullable; import java.io.*; -import java.lang.reflect.Field; import java.net.URL; import java.net.URLConnection; import java.nio.file.Path; @@ -68,8 +67,6 @@ public class BukkitCraftEngine extends CraftEngine { private SchedulerTask tickTask; private boolean successfullyLoaded = false; private boolean successfullyEnabled = false; - private boolean requiresRestart = false; - private boolean hasMod = false; private AntiGriefLib antiGrief; private JavaPlugin javaPlugin; private final Path dataFolderPath; @@ -90,16 +87,6 @@ public class BukkitCraftEngine extends CraftEngine { super.logger = logger; super.platform = new BukkitPlatform(); super.scheduler = new BukkitSchedulerAdapter(this); - // find mod class if present - Class modClass = ReflectionUtils.getClazz(MOD_CLASS); - if (modClass != null) { - Field isSuccessfullyRegistered = ReflectionUtils.getDeclaredField(modClass, "isSuccessfullyRegistered"); - try { - requiresRestart = !(boolean) isSuccessfullyRegistered.get(null); - hasMod = true; - } catch (Exception ignore) { - } - } Class compatibilityClass = Objects.requireNonNull(ReflectionUtils.getClazz(COMPATIBILITY_CLASS), "Compatibility class not found"); try { super.compatibilityManager = (CompatibilityManager) Objects.requireNonNull(ReflectionUtils.getConstructor(compatibilityClass, 0)).newInstance(this); @@ -132,7 +119,6 @@ public class BukkitCraftEngine extends CraftEngine { if (super.blockManager == null) { injectRegistries(); } - if (this.requiresRestart) return; try { WorldStorageInjector.init(); } catch (Exception e) { @@ -177,17 +163,6 @@ public class BukkitCraftEngine extends CraftEngine { return; } this.successfullyEnabled = true; - if (this.requiresRestart) { - logger().warn(" "); - logger().warn(" "); - logger().warn(" "); - logger().warn("This is the first time you have installed CraftEngine. A restart is required to apply the changes."); - logger().warn(" "); - logger().warn(" "); - logger().warn(" "); - Bukkit.getServer().shutdown(); - return; - } if (!this.successfullyLoaded) { logger().severe(" "); logger().severe(" "); @@ -390,14 +365,6 @@ public class BukkitCraftEngine extends CraftEngine { ); } - public boolean hasMod() { - return hasMod; - } - - public boolean requiresRestart() { - return requiresRestart; - } - public AntiGriefLib antiGrief() { if (this.antiGrief == null) { this.antiGrief = AntiGriefLib.builder(this.javaPlugin) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java index 2b3647fa1..1d43f760f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitPlatform.java @@ -1,12 +1,32 @@ package net.momirealms.craftengine.bukkit.plugin; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.Platform; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import org.bukkit.Bukkit; +import java.util.Map; + public class BukkitPlatform implements Platform { @Override public void dispatchCommand(String command) { Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), command); } + + @SuppressWarnings("unchecked") + @Override + public Object nbt2Java(String nbt) { + try { + Object tag = FastNMS.INSTANCE.method$TagParser$parseCompoundFully("{\"root\":" + nbt + "}"); + Map map = (Map) MRegistryOps.NBT.convertTo(MRegistryOps.JAVA, tag); + return map.get("root"); + } catch (CommandSyntaxException e) { + CraftEngine.instance().debug(e::getMessage); + throw new LocalizedResourceConfigException("warning.config.template.argument.default_value.invalid_syntax", e, nbt); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java index 6701320b9..87288628b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/BukkitCommandManager.java @@ -48,6 +48,8 @@ public class BukkitCommandManager extends AbstractCommandManager new DebugSpawnFurnitureCommand(this, plugin), new DebugTargetBlockCommand(this, plugin), new DebugIsSectionInjectedCommand(this, plugin), + new DebugMigrateTemplatesCommand(this, plugin), + new DebugEntityId2UUIDCommand(this, plugin), new TotemAnimationCommand(this, plugin), new EnableResourceCommand(this, plugin), new DisableResourceCommand(this, plugin), diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugEntityId2UUIDCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugEntityId2UUIDCommand.java new file mode 100644 index 000000000..f5bacc952 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugEntityId2UUIDCommand.java @@ -0,0 +1,59 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.bukkit.parser.WorldParser; +import org.incendo.cloud.parser.standard.IntegerParser; + +public class DebugEntityId2UUIDCommand extends BukkitCommandFeature { + + public DebugEntityId2UUIDCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .required("world", WorldParser.worldParser()) + .required("entityId", IntegerParser.integerParser()) + .handler(context -> { + World world = context.get("world"); + int entityId = context.get("entityId"); + Entity entity = FastNMS.INSTANCE.getBukkitEntityById(world, entityId); + if (entity == null) { + context.sender().sendMessage("entity not found"); + return; + } + Location location = entity.getLocation(); + context.sender().sendMessage( + String.format( + """ + =========================== + uuid: %s + name: %s + location: %s,%s,%s + type: %s + =========================== + """, + entity.getUniqueId(), + entity.getName(), + location.x(), location.y(), location.z(), + entity.getType() + ) + ); + }); + } + + @Override + public String getFeatureID() { + return "debug_entity_id_to_uuid"; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugMigrateTemplatesCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugMigrateTemplatesCommand.java new file mode 100644 index 000000000..227b0f19f --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugMigrateTemplatesCommand.java @@ -0,0 +1,60 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.util.FileUtils; +import org.bukkit.command.CommandSender; +import org.incendo.cloud.Command; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DebugMigrateTemplatesCommand extends BukkitCommandFeature { + private static final Pattern PATTERN = Pattern.compile("(? commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { + return builder + .handler(context -> { + for (Pack pack : BukkitCraftEngine.instance().packManager().loadedPacks()) { + for (Path file : FileUtils.getYmlConfigsDeeply(pack.configurationFolder())) { + try { + Files.writeString(file, replacePlaceholders(Files.readString(file))); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + context.sender().sendMessage("Done"); + }); + } + + @Override + public String getFeatureID() { + return "debug_migrate_templates"; + } + + private static String replacePlaceholders(String input) { + if (input == null) { + return null; + } + Matcher matcher = PATTERN.matcher(input); + StringBuilder sb = new StringBuilder(); + while (matcher.find()) { + // 将 {xxx} 替换为 ${xxx} + matcher.appendReplacement(sb, "\\${" + matcher.group(1) + "}"); + } + matcher.appendTail(sb); + return sb.toString(); + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java index 70914aa49..a6333f2d5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugSpawnFurnitureCommand.java @@ -54,7 +54,7 @@ public class DebugSpawnFurnitureCommand extends BukkitCommandFeature return; } } - YamlDocument document = plugin().config().loadYamlData(packMetaPath.toFile()); + YamlDocument document = plugin().config().loadYamlData(packMetaPath); document.set("enable", false); try { document.save(packMetaPath.toFile()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/EnableResourceCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/EnableResourceCommand.java index e565f9935..58960b6bc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/EnableResourceCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/EnableResourceCommand.java @@ -52,7 +52,7 @@ public class EnableResourceCommand extends BukkitCommandFeature { return; } } - YamlDocument document = plugin().config().loadYamlData(packMetaPath.toFile()); + YamlDocument document = plugin().config().loadYamlData(packMetaPath); document.set("enable", true); try { document.save(packMetaPath.toFile()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java index ffe67dcb5..e6b543954 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java @@ -19,6 +19,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; import net.momirealms.craftengine.bukkit.util.NoteBlockChainUpdateUtils; import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ObjectHolder; import net.momirealms.craftengine.core.util.VersionHelper; @@ -36,6 +37,7 @@ public final class BlockGenerator { private static Field field$CraftEngineBlock$behavior; private static Field field$CraftEngineBlock$shape; private static Field field$CraftEngineBlock$isNoteBlock; + private static Field field$CraftEngineBlock$isTripwire; public static void init() throws ReflectiveOperationException { ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); @@ -48,6 +50,7 @@ public final class BlockGenerator { .defineField("behaviorHolder", ObjectHolder.class, Visibility.PUBLIC) .defineField("shapeHolder", ObjectHolder.class, Visibility.PUBLIC) .defineField("isClientSideNoteBlock", boolean.class, Visibility.PUBLIC) + .defineField("isClientSideTripwire", boolean.class, Visibility.PUBLIC) // should always implement this interface .implement(CoreReflections.clazz$Fallable) .implement(CoreReflections.clazz$BonemealableBlock) @@ -55,13 +58,15 @@ public final class BlockGenerator { // internal interfaces .implement(BehaviorHolder.class) .implement(ShapeHolder.class) - .implement(NoteBlockIndicator.class) + .implement(ChainUpdateBlockIndicator.class) .method(ElementMatchers.named("getBehaviorHolder")) .intercept(FieldAccessor.ofField("behaviorHolder")) .method(ElementMatchers.named("getShapeHolder")) .intercept(FieldAccessor.ofField("shapeHolder")) .method(ElementMatchers.named("isNoteBlock")) .intercept(FieldAccessor.ofField("isClientSideNoteBlock")) + .method(ElementMatchers.named("isTripwire")) + .intercept(FieldAccessor.ofField("isClientSideTripwire")) // getShape .method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$getShape)) .intercept(MethodDelegation.to(GetShapeInterceptor.INSTANCE)) @@ -142,6 +147,7 @@ public final class BlockGenerator { field$CraftEngineBlock$behavior = clazz$CraftEngineBlock.getField("behaviorHolder"); field$CraftEngineBlock$shape = clazz$CraftEngineBlock.getField("shapeHolder"); field$CraftEngineBlock$isNoteBlock = clazz$CraftEngineBlock.getField("isClientSideNoteBlock"); + field$CraftEngineBlock$isTripwire = clazz$CraftEngineBlock.getField("isClientSideTripwire"); } public static Object generateBlock(Key replacedBlock, Object ownerBlock, Object properties) throws Throwable { @@ -155,18 +161,28 @@ public final class BlockGenerator { field$CraftEngineBlock$behavior.set(newBlockInstance, behaviorHolder); field$CraftEngineBlock$shape.set(newBlockInstance, shapeHolder); field$CraftEngineBlock$isNoteBlock.set(newBlockInstance, replacedBlock.equals(BlockKeys.NOTE_BLOCK)); + field$CraftEngineBlock$isTripwire.set(newBlockInstance, replacedBlock.equals(BlockKeys.TRIPWIRE)); return newBlockInstance; } public static class UpdateShapeInterceptor { public static final UpdateShapeInterceptor INSTANCE = new UpdateShapeInterceptor(); public static final int levelIndex = VersionHelper.isOrAbove1_21_2() ? 1 : 3; + public static final int directionIndex = VersionHelper.isOrAbove1_21_2() ? 4 : 1; + public static final int posIndex = VersionHelper.isOrAbove1_21_2() ? 3 : 4; @RuntimeType - public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) throws Exception { + public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { ObjectHolder holder = ((BehaviorHolder) thisObj).getBehaviorHolder(); - if (((NoteBlockIndicator) thisObj).isNoteBlock() && CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) { - startNoteBlockChain(args); + ChainUpdateBlockIndicator indicator = (ChainUpdateBlockIndicator) thisObj; + if (indicator.isNoteBlock()) { + if (CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) { + startNoteBlockChain(args); + } + } else if (indicator.isTripwire()) { + if (CoreReflections.clazz$ServerLevel.isInstance(args[posIndex])) { + + } } try { return holder.value().updateShape(thisObj, args, superMethod); @@ -175,30 +191,20 @@ public final class BlockGenerator { return args[0]; } } - } - private static void startNoteBlockChain(Object[] args) throws ReflectiveOperationException { - Object direction; - Object serverLevel; - Object blockPos; - if (VersionHelper.isOrAbove1_21_2()) { - direction = args[4]; - serverLevel = args[1]; - blockPos = args[3]; - } else { - direction = args[1]; - serverLevel = args[3]; - blockPos = args[4]; - } - int id = (int) CoreReflections.field$Direction$data3d.get(direction); - // Y axis - if (id == 0 || id == 1) { - Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel); - FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos); - if (id == 1) { - NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$DOWN, blockPos, 0); - } else { - NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$UP, blockPos, 0); + private static void startNoteBlockChain(Object[] args) { + Object direction = args[directionIndex]; + Object serverLevel = args[levelIndex]; + Object blockPos = args[posIndex]; + // Y axis + if (direction == CoreReflections.instance$Direction$DOWN) { + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel); + FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos); + NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$UP, blockPos, Config.maxNoteBlockChainUpdate()); + } else if (direction == CoreReflections.instance$Direction$UP) { + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel); + FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos); + NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, CoreReflections.instance$Direction$DOWN, blockPos, Config.maxNoteBlockChainUpdate()); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java index 728547596..f8fc33654 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java @@ -8,6 +8,10 @@ public interface InjectedCacheCheck { void recipeType(Object recipeType); + Key customRecipeType(); + + void customRecipeType(Key customRecipeType); + Object lastRecipe(); void lastRecipe(Object lastRecipe); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java index 820b9f556..c05455611 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java @@ -16,6 +16,8 @@ import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRecipeTypes; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.recipe.CustomCookingRecipe; import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; @@ -28,7 +30,6 @@ import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.inventory.ItemStack; -import java.util.List; import java.util.Optional; public class RecipeInjector { @@ -41,17 +42,23 @@ public class RecipeInjector { .name("net.momirealms.craftengine.bukkit.entity.InjectedCacheChecker") .implement(CoreReflections.clazz$RecipeManager$CachedCheck) .implement(InjectedCacheCheck.class) + .defineField("recipeType", Object.class, Visibility.PUBLIC) .method(ElementMatchers.named("recipeType")) .intercept(FieldAccessor.ofField("recipeType")) + + .defineField("customRecipeType", Key.class, Visibility.PUBLIC) + .method(ElementMatchers.named("customRecipeType")) + .intercept(FieldAccessor.ofField("customRecipeType")) + .defineField("lastRecipe", Object.class, Visibility.PUBLIC) .method(ElementMatchers.named("lastRecipe")) .intercept(FieldAccessor.ofField("lastRecipe")) - .method(ElementMatchers.named("setLastRecipe")) - .intercept(FieldAccessor.ofField("lastRecipe")) + .defineField("lastCustomRecipe", Key.class, Visibility.PUBLIC) .method(ElementMatchers.named("lastCustomRecipe")) .intercept(FieldAccessor.ofField("lastCustomRecipe")) + .method(ElementMatchers.named("getRecipeFor").or(ElementMatchers.named("a"))) .intercept(MethodDelegation.to( VersionHelper.isOrAbove1_21_2() ? @@ -73,269 +80,227 @@ public class RecipeInjector { if (clazz$InjectedCacheChecker.isInstance(quickCheck)) return; // already injected Object recipeType = FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$recipeType(entity); InjectedCacheCheck injectedChecker = (InjectedCacheCheck) ReflectionUtils.UNSAFE.allocateInstance(clazz$InjectedCacheChecker); - injectedChecker.recipeType(recipeType); + if (recipeType == MRecipeTypes.SMELTING) { + injectedChecker.customRecipeType(RecipeTypes.SMELTING); + injectedChecker.recipeType(MRecipeTypes.SMELTING); + } else if (recipeType == MRecipeTypes.BLASTING) { + injectedChecker.customRecipeType(RecipeTypes.BLASTING); + injectedChecker.recipeType(MRecipeTypes.BLASTING); + } else if (recipeType == MRecipeTypes.SMOKING) { + injectedChecker.customRecipeType(RecipeTypes.SMOKING); + injectedChecker.recipeType(MRecipeTypes.SMOKING); + } else { + throw new IllegalStateException("RecipeType " + recipeType + " not supported"); + } CoreReflections.field$AbstractFurnaceBlockEntity$quickCheck.set(entity, injectedChecker); } else if (!VersionHelper.isOrAbove1_21_2() && CoreReflections.clazz$CampfireBlockEntity.isInstance(entity)) { Object quickCheck = CoreReflections.field$CampfireBlockEntity$quickCheck.get(entity); if (clazz$InjectedCacheChecker.isInstance(quickCheck)) return; // already injected InjectedCacheCheck injectedChecker = (InjectedCacheCheck) ReflectionUtils.UNSAFE.allocateInstance(clazz$InjectedCacheChecker); + injectedChecker.customRecipeType(RecipeTypes.CAMPFIRE_COOKING); injectedChecker.recipeType(MRecipeTypes.CAMPFIRE_COOKING); CoreReflections.field$CampfireBlockEntity$quickCheck.set(entity, injectedChecker); } } + @SuppressWarnings("DuplicatedCode") public static class GetRecipeForMethodInterceptor1_20 { public static final GetRecipeForMethodInterceptor1_20 INSTANCE = new GetRecipeForMethodInterceptor1_20(); @SuppressWarnings("unchecked") @RuntimeType - public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); + public Object intercept(@This Object thisObj, @AllArguments Object[] args) { InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; - Object type = injectedCacheCheck.recipeType(); - Object lastRecipe = injectedCacheCheck.lastRecipe(); - Optional> optionalRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(mcRecipeManager, type, args[0], args[1], lastRecipe); - if (optionalRecipe.isPresent()) { - Pair pair = optionalRecipe.get(); - Object resourceLocation = pair.getFirst(); - Key recipeId = Key.of(resourceLocation.toString()); - BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); - - ItemStack itemStack; - List items; - if (type == MRecipeTypes.CAMPFIRE_COOKING) { - items = (List) CoreReflections.field$SimpleContainer$items.get(args[0]); - } else { - items = (List) CoreReflections.field$AbstractFurnaceBlockEntity$items.get(args[0]); - } - itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(items.get(0)); - - // it's a recipe from other plugins - boolean isCustom = recipeManager.isCustomRecipe(recipeId); - if (!isCustom) { - injectedCacheCheck.lastRecipe(resourceLocation); - return Optional.of(pair.getSecond()); - } - - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - if (idHolder.isEmpty()) { - return Optional.empty(); - } - - SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); - CustomCookingRecipe ceRecipe; - Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); - if (type == MRecipeTypes.SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.CAMPFIRE_COOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); - } else { - return Optional.empty(); - } - if (ceRecipe == null) { - return Optional.empty(); - } - - // Cache recipes, it might be incorrect on reloading - injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); - // It doesn't matter at all - injectedCacheCheck.lastRecipe(resourceLocation); - return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(pair.getSecond())); - } else { + Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe(); + Optional> optionalRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); + if (optionalRecipe.isEmpty()) { return Optional.empty(); } + + Pair resourceLocationAndRecipe = optionalRecipe.get(); + Object rawRecipeResourceLocation = resourceLocationAndRecipe.getFirst(); + Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString()); + BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); + + boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey); + if (!isCustom) { + injectedCacheCheck.lastRecipe(rawRecipeResourceLocation); + return Optional.of(resourceLocationAndRecipe.getSecond()); + } + + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror( + injectedCacheCheck.recipeType() == MRecipeTypes.CAMPFIRE_COOKING ? + FastNMS.INSTANCE.field$SimpleContainer$items(args[0]).getFirst() : + FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$getItem(args[0], 0) + ); + + Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); + Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); + if (idHolder.isEmpty()) { + return Optional.empty(); + } + + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); + if (ceRecipe == null) { + return Optional.empty(); + } + + injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); + if (!ceRecipe.id().equals(rawRecipeKey)) { + injectedCacheCheck.lastRecipe(KeyUtils.toResourceLocation(ceRecipe.id())); + } + return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)); } } + @SuppressWarnings("DuplicatedCode") public static class GetRecipeForMethodInterceptor1_20_5 { public static final GetRecipeForMethodInterceptor1_20_5 INSTANCE = new GetRecipeForMethodInterceptor1_20_5(); @SuppressWarnings("unchecked") @RuntimeType - public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); + public Object intercept(@This Object thisObj, @AllArguments Object[] args) { InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; - Object type = injectedCacheCheck.recipeType(); - Object lastRecipe = injectedCacheCheck.lastRecipe(); - Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(mcRecipeManager, type, args[0], args[1], lastRecipe); - if (optionalRecipe.isPresent()) { - Object holder = optionalRecipe.get(); - Object id = FastNMS.INSTANCE.field$RecipeHolder$id(holder); - Key recipeId = Key.of(id.toString()); - BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); - - ItemStack itemStack; - List items; - if (type == MRecipeTypes.CAMPFIRE_COOKING) { - items = (List) CoreReflections.field$SimpleContainer$items.get(args[0]); - } else { - items = (List) CoreReflections.field$AbstractFurnaceBlockEntity$items.get(args[0]); - } - itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(items.get(0)); - - // it's a recipe from other plugins - boolean isCustom = recipeManager.isCustomRecipe(recipeId); - if (!isCustom) { - injectedCacheCheck.lastRecipe(id); - return optionalRecipe; - } - - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - if (idHolder.isEmpty()) { - return Optional.empty(); - } - - SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); - CustomCookingRecipe ceRecipe; - Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); - if (type == MRecipeTypes.SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.CAMPFIRE_COOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); - } else { - return Optional.empty(); - } - if (ceRecipe == null) { - return Optional.empty(); - } - - // Cache recipes, it might be incorrect on reloading - injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); - // It doesn't matter at all - injectedCacheCheck.lastRecipe(id); - return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder)); - } else { + Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe(); + Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); + if (optionalRecipe.isEmpty()) { return Optional.empty(); } + + Object rawRecipeHolder = optionalRecipe.get(); + Object rawRecipeResourceLocation = FastNMS.INSTANCE.field$RecipeHolder$id(rawRecipeHolder); + Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString()); + + BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror( + injectedCacheCheck.recipeType() == MRecipeTypes.CAMPFIRE_COOKING ? + FastNMS.INSTANCE.field$SimpleContainer$items(args[0]).getFirst() : + FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$getItem(args[0], 0) + ); + + boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey); + if (!isCustom) { + injectedCacheCheck.lastRecipe(rawRecipeResourceLocation); + return optionalRecipe; + } + + Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); + Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); + if (idHolder.isEmpty()) { + return Optional.empty(); + } + + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); + if (ceRecipe == null) { + return Optional.empty(); + } + + injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); + if (!ceRecipe.id().equals(rawRecipeKey)) { + injectedCacheCheck.lastRecipe(KeyUtils.toResourceLocation(ceRecipe.id())); + } + return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)); } } + @SuppressWarnings("DuplicatedCode") public static class GetRecipeForMethodInterceptor1_21 { public static final GetRecipeForMethodInterceptor1_21 INSTANCE = new GetRecipeForMethodInterceptor1_21(); @SuppressWarnings("unchecked") @RuntimeType - public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); + public Object intercept(@This Object thisObj, @AllArguments Object[] args) { InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; - Object type = injectedCacheCheck.recipeType(); - Object lastRecipe = injectedCacheCheck.lastRecipe(); - Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(mcRecipeManager, type, args[0], args[1], lastRecipe); - if (optionalRecipe.isPresent()) { - Object holder = optionalRecipe.get(); - Object id = FastNMS.INSTANCE.field$RecipeHolder$id(holder); - Key recipeId = Key.of(id.toString()); - BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); - ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(CoreReflections.field$SingleRecipeInput$item.get(args[0])); - - // it's a recipe from other plugins - boolean isCustom = recipeManager.isCustomRecipe(recipeId); - if (!isCustom) { - injectedCacheCheck.lastRecipe(id); - return optionalRecipe; - } - - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - if (idHolder.isEmpty()) { - return Optional.empty(); - } - - SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); - CustomCookingRecipe ceRecipe; - Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); - if (type == MRecipeTypes.SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.CAMPFIRE_COOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); - } else { - return Optional.empty(); - } - if (ceRecipe == null) { - return Optional.empty(); - } - - // Cache recipes, it might be incorrect on reloading - injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); - // It doesn't matter at all - injectedCacheCheck.lastRecipe(id); - return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder)); - } else { + Object lastRecipeResourceLocation = injectedCacheCheck.lastRecipe(); + Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceLocation); + if (optionalRecipe.isEmpty()) { return Optional.empty(); } + + Object rawRecipeHolder = optionalRecipe.get(); + Object rawRecipeResourceLocation = FastNMS.INSTANCE.field$RecipeHolder$id(rawRecipeHolder); + Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString()); + + BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); + boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey); + if (!isCustom) { + injectedCacheCheck.lastRecipe(rawRecipeResourceLocation); + return optionalRecipe; + } + + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$SingleRecipeInput$item(args[0])); + Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); + Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); + if (idHolder.isEmpty()) { + return Optional.empty(); + } + + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); + if (ceRecipe == null) { + return Optional.empty(); + } + + injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); + if (!ceRecipe.id().equals(rawRecipeKey)) { + injectedCacheCheck.lastRecipe(KeyUtils.toResourceLocation(ceRecipe.id())); + } + return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)); } } + @SuppressWarnings("DuplicatedCode") public static class GetRecipeForMethodInterceptor1_21_2 { public static final GetRecipeForMethodInterceptor1_21_2 INSTANCE = new GetRecipeForMethodInterceptor1_21_2(); @SuppressWarnings("unchecked") @RuntimeType - public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); + public Object intercept(@This Object thisObj, @AllArguments Object[] args) { InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; - Object type = injectedCacheCheck.recipeType(); - Object lastRecipe = injectedCacheCheck.lastRecipe(); - Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(mcRecipeManager, type, args[0], args[1], lastRecipe); - if (optionalRecipe.isPresent()) { - Object holder = optionalRecipe.get(); - Object id = FastNMS.INSTANCE.field$RecipeHolder$id(holder); - Object resourceLocation = FastNMS.INSTANCE.field$ResourceKey$location(id); - Key recipeId = Key.of(resourceLocation.toString()); - BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); - ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(CoreReflections.field$SingleRecipeInput$item.get(args[0])); - - // it's a recipe from other plugins - boolean isCustom = recipeManager.isCustomRecipe(recipeId); - if (!isCustom) { - injectedCacheCheck.lastRecipe(id); - return optionalRecipe; - } - - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - if (idHolder.isEmpty()) { - return Optional.empty(); - } - - SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); - CustomCookingRecipe ceRecipe; - Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); - if (type == MRecipeTypes.SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); - } else if (type == MRecipeTypes.SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); - } else { - return Optional.empty(); - } - if (ceRecipe == null) { - return Optional.empty(); - } - - // Cache recipes, it might be incorrect on reloading - injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); - // It doesn't matter at all - injectedCacheCheck.lastRecipe(id); - return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder)); - } else { + Object lastRecipeResourceKey = injectedCacheCheck.lastRecipe(); + Optional optionalRecipe = (Optional) FastNMS.INSTANCE.method$RecipeManager$getRecipeFor(BukkitRecipeManager.nmsRecipeManager(), injectedCacheCheck.recipeType(), args[0], args[1], lastRecipeResourceKey); + if (optionalRecipe.isEmpty()) { return Optional.empty(); } + + // 获取配方的基础信息 + Object recipeHolder = optionalRecipe.get(); + Object rawRecipeResourceKey = FastNMS.INSTANCE.field$RecipeHolder$id(recipeHolder); + Object rawRecipeResourceLocation = FastNMS.INSTANCE.field$ResourceKey$location(rawRecipeResourceKey); + Key rawRecipeKey = Key.of(rawRecipeResourceLocation.toString()); + + BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); + // 来自其他插件注册的自定义配方 + boolean isCustom = recipeManager.isCustomRecipe(rawRecipeKey); + if (!isCustom) { + injectedCacheCheck.lastRecipe(rawRecipeResourceKey); + return optionalRecipe; + } + + // 获取唯一内存地址id + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$SingleRecipeInput$item(args[0])); + Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); + Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); + if (idHolder.isEmpty()) { + return Optional.empty(); + } + + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); + // 这个ce配方并不存在,那么应该返回空 + if (ceRecipe == null) { + return Optional.empty(); + } + + // 记录上一次使用的配方(ce) + injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); + // 更新上一次使用的配方(nms) + if (!ceRecipe.id().equals(rawRecipeKey)) { + injectedCacheCheck.lastRecipe(FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.RECIPE, KeyUtils.toResourceLocation(ceRecipe.id()))); + } + return Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java index 02a99e042..285d026c8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java @@ -17,6 +17,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.EmptyBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -220,23 +221,36 @@ public class WorldStorageInjector { CESection section = holder.ceSection(); // 如果是原版方块 if (BlockStateUtils.isVanillaBlock(stateId)) { - // 那么应该情况自定义块 + // 那么应该清空自定义块 ImmutableBlockState previous = section.setBlockState(x, y, z, EmptyBlock.STATE); - // 如果先前不是空气则标记 + // 处理 自定义块 -> 原版块 if (!previous.isEmpty()) { holder.ceChunk().setDirty(true); if (Config.enableLightSystem()) { - updateLightIfChanged(holder, previousState, newState, newState, x, y, z); + // 自定义块到原版块,只需要判断旧块是否和客户端一直 + BlockStateWrapper wrapper = previous.vanillaBlockState(); + if (wrapper != null) { + updateLight(holder, wrapper.handle(), previousState, x, y, z); + } } } } else { ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); ImmutableBlockState previousImmutableBlockState = section.setBlockState(x, y, z, immutableBlockState); if (previousImmutableBlockState == immutableBlockState) return; + // 处理 自定义块到自定义块或原版块到自定义块 holder.ceChunk().setDirty(true); + // 不可能!绝对不可能! + if (immutableBlockState.isEmpty()) return; // 如果新方块的光照属性和客户端认为的不同 - if (Config.enableLightSystem() && !immutableBlockState.isEmpty()) { - updateLightIfChanged(holder, previousState, immutableBlockState.vanillaBlockState().handle(), newState, x, y, z); + if (Config.enableLightSystem()) { + if (previousImmutableBlockState.isEmpty()) { + // 原版块到自定义块,只需要判断新块是否和客户端视觉一致 + updateLight(holder, immutableBlockState.vanillaBlockState().handle(), newState, x, y, z); + } else { + // 自定义块到自定义块 + updateLight$complex(holder, immutableBlockState.vanillaBlockState().handle(), newState, previousState, x, y, z); + } } } } catch (Exception e) { @@ -244,17 +258,31 @@ public class WorldStorageInjector { } } - protected static void updateLightIfChanged(@This InjectedHolder thisObj, Object oldServerSideState, Object clientSideState, Object serverSideState, int x, int y, int z) { + @SuppressWarnings("DuplicatedCode") + protected static void updateLight(@This InjectedHolder thisObj, Object clientState, Object serverState, int x, int y, int z) { CEWorld world = thisObj.ceChunk().world(); Object blockPos = LocationUtils.toBlockPos(x, y, z); Object serverWorld = world.world().serverWorld(); - if (clientSideState != serverSideState && FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(clientSideState, serverSideState, serverWorld, blockPos)) { + if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(serverState, clientState, serverWorld, blockPos)) { + SectionPos sectionPos = thisObj.cePos(); + List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15); + world.sectionLightUpdated(pos); + } + } + + @SuppressWarnings("DuplicatedCode") + protected static void updateLight$complex(@This InjectedHolder thisObj, Object newClientState, Object newServerState, Object oldServerState, int x, int y, int z) { + CEWorld world = thisObj.ceChunk().world(); + Object blockPos = LocationUtils.toBlockPos(x, y, z); + Object serverWorld = world.world().serverWorld(); + // 如果客户端新状态和服务端新状态光照属性不同 + if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(newClientState, newServerState, serverWorld, blockPos)) { SectionPos sectionPos = thisObj.cePos(); List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15); world.sectionLightUpdated(pos); return; } - if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(oldServerSideState, serverSideState, serverWorld, blockPos)) { + if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(newServerState, oldServerState, serverWorld, blockPos)) { SectionPos sectionPos = thisObj.cePos(); List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15); world.sectionLightUpdated(pos); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 0e6a33c6e..b69f40300 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -82,7 +82,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static final String CONNECTION_HANDLER_NAME = "craftengine_connection_handler"; private static final String SERVER_CHANNEL_HANDLER_NAME = "craftengine_server_channel_handler"; - private static final String PLAYER_CHANNEL_HANDLER_NAME = "craftengine_player_packet_handler"; + private static final String PLAYER_CHANNEL_HANDLER_NAME = "craftengine_player_channel_handler"; private static final String PACKET_ENCODER = "craftengine_encoder"; private static final String PACKET_DECODER = "craftengine_decoder"; @@ -147,9 +147,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.SET_CREATIVE_SLOT, NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket); registerNMSPacketConsumer(PacketConsumers.LOGIN, NetworkReflections.clazz$ClientboundLoginPacket); registerNMSPacketConsumer(PacketConsumers.RESPAWN, NetworkReflections.clazz$ClientboundRespawnPacket); - registerNMSPacketConsumer(PacketConsumers.INTERACT_ENTITY, NetworkReflections.clazz$ServerboundInteractPacket); registerNMSPacketConsumer(PacketConsumers.SYNC_ENTITY_POSITION, NetworkReflections.clazz$ClientboundEntityPositionSyncPacket); - registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos); registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_ENTITY, NetworkReflections.clazz$ServerboundPickItemFromEntityPacket); registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, NetworkReflections.clazz$ServerboundRenameItemPacket); registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, NetworkReflections.clazz$ServerboundSignUpdatePacket); @@ -161,6 +159,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, NetworkReflections.clazz$ServerboundResourcePackPacket); registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, NetworkReflections.clazz$ClientboundEntityEventPacket); registerNMSPacketConsumer(PacketConsumers.MOVE_POS_AND_ROTATE_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$PosRot); + registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos); registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); @@ -177,7 +176,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_OBJECTIVE_1_20_3 : PacketConsumers.SET_OBJECTIVE_1_20, this.packetIds.clientboundSetObjectivePacket()); registerS2CByteBufPacketConsumer(PacketConsumers.SET_SCORE_1_20_3, VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1); registerS2CByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY_BYTEBUFFER, this.packetIds.clientboundAddEntityPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY, this.packetIds.clientboundAddEntityPacket()); registerS2CByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket()); registerS2CByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket()); registerS2CByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_CONTENT, this.packetIds.clientboundContainerSetContentPacket()); @@ -187,6 +186,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerS2CByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY_1_21_2, this.packetIds.clientboundSetPlayerInventoryPacket()); registerC2SByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket()); registerC2SByteBufPacketConsumer(PacketConsumers.CONTAINER_CLICK_1_20, this.packetIds.serverboundContainerClickPacket()); + registerC2SByteBufPacketConsumer(PacketConsumers.INTERACT_ENTITY, this.packetIds.serverboundInteractPacket()); } public static BukkitNetworkManager instance() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index 4e9c0a759..df11ad10b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -70,7 +70,6 @@ import org.bukkit.util.RayTraceResult; import org.bukkit.util.Vector; import org.jetbrains.annotations.Nullable; -import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.function.BiConsumer; @@ -85,7 +84,7 @@ public class PacketConsumers { public static void initEntities(int registrySize) { ADD_ENTITY_HANDLERS = new BukkitNetworkManager.Handlers[registrySize]; Arrays.fill(ADD_ENTITY_HANDLERS, BukkitNetworkManager.Handlers.DO_NOTHING); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$FALLING_BLOCK$registryId] = (user, event) -> { + ADD_ENTITY_HANDLERS[MEntityTypes.FALLING_BLOCK$registryId] = (user, event) -> { FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); UUID uuid = buf.readUUID(); @@ -122,28 +121,27 @@ public class PacketConsumers { } }; - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$BLOCK_DISPLAY$registryId] = simpleAddEntityHandler(BlockDisplayPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ITEM_DISPLAY$registryId] = simpleAddEntityHandler(ItemDisplayPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$SMALL_FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$EGG$registryId] = createOptionalCustomProjectileEntityHandler(); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ENDER_PEARL$registryId] = createOptionalCustomProjectileEntityHandler(); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$EXPERIENCE_BOTTLE$registryId] = createOptionalCustomProjectileEntityHandler(); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$SNOWBALL$registryId] = createOptionalCustomProjectileEntityHandler(); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$POTION$registryId] = createOptionalCustomProjectileEntityHandler(); - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler(); + ADD_ENTITY_HANDLERS[MEntityTypes.BLOCK_DISPLAY$registryId] = simpleAddEntityHandler(BlockDisplayPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(); + ADD_ENTITY_HANDLERS[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(); + ADD_ENTITY_HANDLERS[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(); + ADD_ENTITY_HANDLERS[MEntityTypes.SMALL_FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(); + ADD_ENTITY_HANDLERS[MEntityTypes.EGG$registryId] = createOptionalCustomProjectileEntityHandler(); + ADD_ENTITY_HANDLERS[MEntityTypes.ENDER_PEARL$registryId] = createOptionalCustomProjectileEntityHandler(); + ADD_ENTITY_HANDLERS[MEntityTypes.EXPERIENCE_BOTTLE$registryId] = createOptionalCustomProjectileEntityHandler(); + ADD_ENTITY_HANDLERS[MEntityTypes.SNOWBALL$registryId] = createOptionalCustomProjectileEntityHandler(); + ADD_ENTITY_HANDLERS[MEntityTypes.POTION$registryId] = createOptionalCustomProjectileEntityHandler(); + ADD_ENTITY_HANDLERS[MEntityTypes.TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler(); if (VersionHelper.isOrAbove1_20_5()) { - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); } - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$ITEM_DISPLAY$registryId] = (user, event) -> { + ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_DISPLAY$registryId] = (user, event) -> { FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); @@ -153,10 +151,12 @@ public class PacketConsumers { if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { event.setCancelled(true); } + } else { + user.entityPacketHandlers().put(id, ItemDisplayPacketHandler.INSTANCE); } }; - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$INTERACTION$registryId] = (user, event) -> { - if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.instance$EntityType$INTERACTION) return; + ADD_ENTITY_HANDLERS[MEntityTypes.INTERACTION$registryId] = (user, event) -> { + if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.INTERACTION) return; FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); // Cancel collider entity packet @@ -166,8 +166,8 @@ public class PacketConsumers { user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); } }; - ADD_ENTITY_HANDLERS[MEntityTypes.instance$EntityType$OAK_BOAT$registryId] = (user, event) -> { - if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.instance$EntityType$OAK_BOAT) return; + ADD_ENTITY_HANDLERS[MEntityTypes.OAK_BOAT$registryId] = (user, event) -> { + if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.OAK_BOAT) return; FriendlyByteBuf buf = event.getBuffer(); int id = buf.readVarInt(); // Cancel collider entity packet @@ -1106,13 +1106,13 @@ public class PacketConsumers { Object blockPos = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$pos(packet); BlockPos pos = LocationUtils.fromBlockPos(blockPos); if (VersionHelper.isFolia()) { - BukkitCraftEngine.instance().scheduler().sync().run(() -> { + platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { try { handlePlayerActionPacketOnMainThread(player, world, pos, packet); } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundPlayerActionPacket", e); } - }, world, pos.x() >> 4, pos.z() >> 4); + }, () -> {}); } else { handlePlayerActionPacketOnMainThread(player, world, pos, packet); } @@ -1172,21 +1172,21 @@ public class PacketConsumers { public static final TriConsumer HELLO_C2S = (user, event, packet) -> { try { BukkitServerPlayer player = (BukkitServerPlayer) user; - String name = (String) NetworkReflections.field$ServerboundHelloPacket$name.get(packet); + String name = (String) NetworkReflections.methodHandle$ServerboundHelloPacket$nameGetter.invokeExact(packet); player.setName(name); if (VersionHelper.isOrAbove1_20_2()) { - UUID uuid = (UUID) NetworkReflections.field$ServerboundHelloPacket$uuid.get(packet); + UUID uuid = (UUID) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); player.setUUID(uuid); } else { @SuppressWarnings("unchecked") - Optional uuid = (Optional) NetworkReflections.field$ServerboundHelloPacket$uuid.get(packet); + Optional uuid = (Optional) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); if (uuid.isPresent()) { player.setUUID(uuid.get()); } else { player.setUUID(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8))); } } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundHelloPacket", e); } }; @@ -1223,10 +1223,10 @@ public class PacketConsumers { player.clearView(); Object dimensionKey; if (!VersionHelper.isOrAbove1_20_2()) { - dimensionKey = NetworkReflections.field$ClientboundRespawnPacket$dimension.get(packet); + dimensionKey = NetworkReflections.methodHandle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet); } else { - Object commonInfo = NetworkReflections.field$ClientboundRespawnPacket$commonPlayerSpawnInfo.get(packet); - dimensionKey = NetworkReflections.field$CommonPlayerSpawnInfo$dimension.get(commonInfo); + Object commonInfo = NetworkReflections.methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); + dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); } Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); @@ -1237,7 +1237,7 @@ public class PacketConsumers { } else { CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket: World " + location + " does not exist"); } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket", e); } }; @@ -1251,10 +1251,10 @@ public class PacketConsumers { if (BukkitNetworkManager.hasViaVersion()) { user.setProtocolVersion(CraftEngine.instance().compatibilityManager().getPlayerProtocolVersion(player.uuid())); } - dimensionKey = NetworkReflections.field$ClientboundLoginPacket$dimension.get(packet); + dimensionKey = NetworkReflections.methodHandle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet); } else { - Object commonInfo = NetworkReflections.field$ClientboundLoginPacket$commonPlayerSpawnInfo.get(packet); - dimensionKey = NetworkReflections.field$CommonPlayerSpawnInfo$dimension.get(commonInfo); + Object commonInfo = NetworkReflections.methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); + dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); } Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); @@ -1265,7 +1265,7 @@ public class PacketConsumers { } else { CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket: World " + location + " does not exist"); } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket", e); } }; @@ -1282,25 +1282,25 @@ public class PacketConsumers { player.platformPlayer().getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { try { handleSetCreativeSlotPacketOnMainThread(player, packet); - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); } }, () -> {}); } else { handleSetCreativeSlotPacketOnMainThread(player, packet); } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); } }; - private static void handleSetCreativeSlotPacketOnMainThread(BukkitServerPlayer player, Object packet) throws Exception { + private static void handleSetCreativeSlotPacketOnMainThread(BukkitServerPlayer player, Object packet) throws Throwable { Player bukkitPlayer = player.platformPlayer(); if (bukkitPlayer == null) return; if (bukkitPlayer.getGameMode() != GameMode.CREATIVE) return; - int slot = VersionHelper.isOrAbove1_20_5() ? NetworkReflections.field$ServerboundSetCreativeModeSlotPacket$slotNum.getShort(packet) : NetworkReflections.field$ServerboundSetCreativeModeSlotPacket$slotNum.getInt(packet); + int slot = VersionHelper.isOrAbove1_20_5() ? (short) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet) : (int) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet); if (slot < 36 || slot > 44) return; - ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.field$ServerboundSetCreativeModeSlotPacket$itemStack.get(packet)); + ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet)); if (ItemUtils.isEmpty(item)) return; if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) { return; @@ -1373,14 +1373,14 @@ public class PacketConsumers { if (!user.isOnline()) return; Player player = (Player) user.platformPlayer(); if (player == null) return; - Object pos = NetworkReflections.field$ServerboundPickItemFromBlockPacket$pos.get(packet); + Object pos = NetworkReflections.methodHandle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet); if (VersionHelper.isFolia()) { int x = FastNMS.INSTANCE.field$Vec3i$x(pos); int z = FastNMS.INSTANCE.field$Vec3i$z(pos); BukkitCraftEngine.instance().scheduler().sync().run(() -> { try { handlePickItemFromBlockPacketOnMainThread(player, pos); - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e); } }, player.getWorld(), x >> 4, z >> 4); @@ -1388,17 +1388,17 @@ public class PacketConsumers { BukkitCraftEngine.instance().scheduler().sync().run(() -> { try { handlePickItemFromBlockPacketOnMainThread(player, pos); - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e); } }); } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e); } }; - private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Exception { + private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Throwable { Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, pos); ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); @@ -1411,7 +1411,7 @@ public class PacketConsumers { // 1.21.4+ public static final TriConsumer PICK_ITEM_FROM_ENTITY = (user, event, packet) -> { try { - int entityId = (int) NetworkReflections.field$ServerboundPickItemFromEntityPacket$id.get(packet); + int entityId = (int) NetworkReflections.methodHandle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet); BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); if (furniture == null) return; Player player = (Player) user.platformPlayer(); @@ -1420,7 +1420,7 @@ public class PacketConsumers { player.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { try { handlePickItemFromEntityOnMainThread(player, furniture); - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e); } }, () -> {}); @@ -1428,23 +1428,23 @@ public class PacketConsumers { BukkitCraftEngine.instance().scheduler().sync().run(() -> { try { handlePickItemFromEntityOnMainThread(player, furniture); - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e); } }); } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e); } }; - private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Exception { + private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Throwable { Key itemId = furniture.config().settings().itemId(); if (itemId == null) return; pickItem(player, itemId, null, FastNMS.INSTANCE.method$CraftEntity$getHandle(furniture.baseEntity())); } - private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws IllegalAccessException, InvocationTargetException { + private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws Throwable { ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, BukkitCraftEngine.instance().adapt(player)); if (itemStack == null) { CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); @@ -1453,15 +1453,15 @@ public class PacketConsumers { assert CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem != null; if (VersionHelper.isOrAbove1_21_5()) { CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( - CoreReflections.field$ServerPlayer$connection.get(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), + CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack), blockPos, entity, true); } else { CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( - CoreReflections.field$ServerPlayer$connection.get(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)); + CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)); } } - public static final BiConsumer ADD_ENTITY_BYTEBUFFER = (user, event) -> { + public static final BiConsumer ADD_ENTITY = (user, event) -> { try { FriendlyByteBuf buf = event.getBuffer(); buf.readVarInt(); @@ -1509,83 +1509,108 @@ public class PacketConsumers { } }; - public static final TriConsumer INTERACT_ENTITY = (user, event, packet) -> { + public static final BiConsumer INTERACT_ENTITY = (user, event) -> { try { - Player player = (Player) user.platformPlayer(); - if (player == null) return; - int entityId; - if (BukkitNetworkManager.hasModelEngine()) { - int fakeId = FastNMS.INSTANCE.field$ServerboundInteractPacket$entityId(packet); - entityId = CraftEngine.instance().compatibilityManager().interactionToBaseEntity(fakeId); - } else { - entityId = FastNMS.INSTANCE.field$ServerboundInteractPacket$entityId(packet); - } + FriendlyByteBuf buf = event.getBuffer(); + int entityId = BukkitNetworkManager.hasModelEngine() ? + CraftEngine.instance().compatibilityManager().interactionToBaseEntity(buf.readVarInt()) : + buf.readVarInt(); BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); if (furniture == null) return; - Object action = NetworkReflections.field$ServerboundInteractPacket$action.get(packet); - Object actionType = NetworkReflections.method$ServerboundInteractPacket$Action$getType.invoke(action); - if (actionType == null) return; - Location location = furniture.baseEntity().getLocation(); + int actionType = buf.readVarInt(); BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; if (serverPlayer.isSpectatorMode()) return; - BukkitCraftEngine.instance().scheduler().sync().run(() -> { - if (actionType == NetworkReflections.instance$ServerboundInteractPacket$ActionType$ATTACK) { + Player platformPlayer = serverPlayer.platformPlayer(); + Location location = furniture.baseEntity().getLocation(); + + Runnable mainThreadTask; + if (actionType == 1) { + // ATTACK + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeBoolean(usingSecondaryAction); + } + + mainThreadTask = () -> { // todo 冒险模式破坏工具白名单 - if (serverPlayer.isAdventureMode()) return; - if (furniture.isValid()) { - if (!BukkitCraftEngine.instance().antiGrief().canBreak(player, location)) { - return; - } - FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture); - if (EventUtils.fireAndCheckCancel(breakEvent)) { - return; - } + if (serverPlayer.isAdventureMode() || + !furniture.isValid() || + !BukkitCraftEngine.instance().antiGrief().canBreak(platformPlayer, location) + ) return; - // execute functions - PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withParameter(DirectContextParameters.FURNITURE, furniture) - .withParameter(DirectContextParameters.POSITION, furniture.position()) - ); - furniture.config().execute(context, EventTrigger.LEFT_CLICK); - furniture.config().execute(context, EventTrigger.BREAK); + FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture); + if (EventUtils.fireAndCheckCancel(breakEvent)) + return; - CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); + Cancellable cancellable = Cancellable.of(breakEvent::isCancelled, breakEvent::setCancelled); + // execute functions + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.HAND, InteractionHand.MAIN_HAND) + .withParameter(DirectContextParameters.ITEM_IN_HAND, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)) + .withParameter(DirectContextParameters.POSITION, furniture.position()) + ); + furniture.config().execute(context, EventTrigger.LEFT_CLICK); + furniture.config().execute(context, EventTrigger.BREAK); + if (cancellable.isCancelled()) { + return; } - } else if (actionType == NetworkReflections.instance$ServerboundInteractPacket$ActionType$INTERACT_AT) { - InteractionHand hand; - Location interactionPoint; - try { - Object interactionHand = NetworkReflections.field$ServerboundInteractPacket$InteractionAtLocationAction$hand.get(action); - hand = interactionHand == CoreReflections.instance$InteractionHand$MAIN_HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; - Object vec3 = NetworkReflections.field$ServerboundInteractPacket$InteractionAtLocationAction$location.get(action); - double x = FastNMS.INSTANCE.field$Vec3$x(vec3); - double y = FastNMS.INSTANCE.field$Vec3$y(vec3); - double z = FastNMS.INSTANCE.field$Vec3$z(vec3); - interactionPoint = new Location(location.getWorld(), x, y, z); - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Failed to get interaction hand from interact packet", e); - } + CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); + }; + } else if (actionType == 2) { + // INTERACT_AT + float x = buf.readFloat(); + float y = buf.readFloat(); + float z = buf.readFloat(); + Location interactionPoint = new Location(platformPlayer.getWorld(), x, y, z); + InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeFloat(x).writeFloat(y).writeFloat(z); + buf.writeVarInt(hand == InteractionHand.MAIN_HAND ? 0 : 1); + buf.writeBoolean(usingSecondaryAction); + } + + mainThreadTask = () -> { FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint); if (EventUtils.fireAndCheckCancel(interactEvent)) { return; } + Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); + Cancellable cancellable = Cancellable.of(interactEvent::isCancelled, interactEvent::setCancelled); // execute functions PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.EVENT, cancellable) .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.HAND, hand) .withParameter(DirectContextParameters.POSITION, furniture.position()) ); furniture.config().execute(context, EventTrigger.RIGHT_CLICK); + if (cancellable.isCancelled()) { + return; + } - if (player.isSneaking()) { + // 必须从网络包层面处理,否则无法获取交互的具体实体 + if (serverPlayer.isSecondaryUseActive() && itemInHand != null) { // try placing another furniture above it AABB hitBox = furniture.aabbByEntityId(entityId); if (hitBox == null) return; - Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); - if (itemInHand == null) return; - Optional> optionalCustomitem = itemInHand.getCustomItem(); - Location eyeLocation = player.getEyeLocation(); + Optional> optionalCustomItem = itemInHand.getCustomItem(); + Location eyeLocation = platformPlayer.getEyeLocation(); Vector direction = eyeLocation.getDirection(); Location endLocation = eyeLocation.clone(); endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange())); @@ -1594,8 +1619,8 @@ public class PacketConsumers { return; } EntityHitResult hitResult = result.get(); - if (optionalCustomitem.isPresent() && !optionalCustomitem.get().behaviors().isEmpty()) { - for (ItemBehavior behavior : optionalCustomitem.get().behaviors()) { + if (optionalCustomItem.isPresent() && !optionalCustomItem.get().behaviors().isEmpty()) { + for (ItemBehavior behavior : optionalCustomItem.get().behaviors()) { if (behavior instanceof FurnitureItemBehavior) { behavior.useOnBlock(new UseOnContext(serverPlayer, InteractionHand.MAIN_HAND, new BlockHitResult(hitResult.hitLocation(), hitResult.direction(), BlockPos.fromVec3d(hitResult.hitLocation()), false))); return; @@ -1604,7 +1629,12 @@ public class PacketConsumers { } // now simulate vanilla item behavior serverPlayer.setResendSound(); - FastNMS.INSTANCE.simulateInteraction(serverPlayer.serverPlayer(), DirectionUtils.toNMSDirection(hitResult.direction()), hitResult.hitLocation().x, hitResult.hitLocation().y, hitResult.hitLocation().z, LocationUtils.toBlockPos(hitResult.blockPos())); + FastNMS.INSTANCE.simulateInteraction( + serverPlayer.serverPlayer(), + DirectionUtils.toNMSDirection(hitResult.direction()), + hitResult.hitLocation().x, hitResult.hitLocation().y, hitResult.hitLocation().z, + LocationUtils.toBlockPos(hitResult.blockPos()) + ); } else { furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { if (furniture.tryOccupySeat(seatPos)) { @@ -1612,9 +1642,30 @@ public class PacketConsumers { } }); } + }; + } else if (actionType == 0) { + int hand = buf.readVarInt(); + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeVarInt(hand); + buf.writeBoolean(usingSecondaryAction); } - }, player.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); - } catch (Exception e) { + return; + } else { + return; + } + + if (VersionHelper.isFolia()) { + platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), t -> mainThreadTask.run(), () -> {}); + } else { + BukkitCraftEngine.instance().scheduler().executeSync(mainThreadTask); + } + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundInteractPacket", e); } }; @@ -1699,20 +1750,20 @@ public class PacketConsumers { if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_ANVIL)) { return; } - String message = (String) NetworkReflections.field$ServerboundRenameItemPacket$name.get(packet); + String message = (String) NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet); if (message != null && !message.isEmpty()) { // check bypass FontManager manager = CraftEngine.instance().fontManager(); IllegalCharacterProcessResult result = manager.processIllegalCharacters(message); if (result.has()) { try { - NetworkReflections.field$ServerboundRenameItemPacket$name.set(packet, result.text()); + NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text()); } catch (ReflectiveOperationException e) { CraftEngine.instance().logger().warn("Failed to replace chat", e); } } } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e); } }; @@ -1725,7 +1776,7 @@ public class PacketConsumers { if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_SIGN)) { return; } - String[] lines = (String[]) NetworkReflections.field$ServerboundSignUpdatePacket$lines.get(packet); + String[] lines = (String[]) NetworkReflections.methodHandle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet); FontManager manager = CraftEngine.instance().fontManager(); if (!manager.isDefaultFontInUse()) return; for (int i = 0; i < lines.length; i++) { @@ -1737,7 +1788,7 @@ public class PacketConsumers { } } } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundSignUpdatePacket", e); } }; @@ -1756,9 +1807,9 @@ public class PacketConsumers { boolean changed = false; - List pages = (List) NetworkReflections.field$ServerboundEditBookPacket$pages.get(packet); + List pages = (List) NetworkReflections.methodHandle$ServerboundEditBookPacket$pagesGetter.invokeExact(packet); List newPages = new ArrayList<>(pages.size()); - Optional title = (Optional) NetworkReflections.field$ServerboundEditBookPacket$title.get(packet); + Optional title = (Optional) NetworkReflections.methodHandle$ServerboundEditBookPacket$titleGetter.invokeExact(packet); Optional newTitle; if (title.isPresent()) { @@ -1782,13 +1833,13 @@ public class PacketConsumers { if (changed) { Object newPacket = NetworkReflections.constructor$ServerboundEditBookPacket.newInstance( - NetworkReflections.field$ServerboundEditBookPacket$slot.get(packet), + (int) NetworkReflections.methodHandle$ServerboundEditBookPacket$slotGetter.invokeExact(packet), newPages, newTitle ); event.replacePacket(newPacket); } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundEditBookPacket", e); } }; @@ -1815,7 +1866,7 @@ public class PacketConsumers { public static final TriConsumer CUSTOM_PAYLOAD = (user, event, packet) -> { try { if (!VersionHelper.isOrAbove1_20_5()) return; - Object payload = NetworkReflections.field$ServerboundCustomPayloadPacket$payload.get(packet); + Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { Payload discardedPayload = DiscardedPayload.from(payload); if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) @@ -1844,7 +1895,7 @@ public class PacketConsumers { } } } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e); } }; @@ -2234,9 +2285,9 @@ public class PacketConsumers { public static final TriConsumer HANDSHAKE_C2S = (user, event, packet) -> { try { if (BukkitNetworkManager.hasViaVersion()) return; - int protocolVersion = NetworkReflections.field$ClientIntentionPacket$protocolVersion.getInt(packet); + int protocolVersion = (int) NetworkReflections.methodHandle$ClientIntentionPacket$protocolVersionGetter.invokeExact(packet); user.setProtocolVersion(protocolVersion); - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ClientIntentionPacket", e); } }; @@ -2254,7 +2305,7 @@ public class PacketConsumers { public static final TriConsumer RESOURCE_PACK_RESPONSE = (user, event, packet) -> { try { if (user.sentResourcePack() || !Config.sendPackOnJoin() || !Config.kickOnDeclined()) return; - Object action = NetworkReflections.field$ServerboundResourcePackPacket$action.get(packet); + Object action = NetworkReflections.methodHandle$ServerboundResourcePackPacket$actionGetter.invokeExact(packet); if (action == null) return; if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DECLINED || action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD) { @@ -2267,7 +2318,7 @@ public class PacketConsumers { if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$SUCCESSFULLY_LOADED) { user.setSentResourcePack(true); } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundResourcePackPacket", e); } }; @@ -2276,28 +2327,17 @@ public class PacketConsumers { try { Object player = user.serverPlayer(); if (player == null) return; - int entityId = NetworkReflections.field$ClientboundEntityEventPacket$entityId.getInt(packet); + int entityId = (int) NetworkReflections.methodHandle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet); if (entityId != FastNMS.INSTANCE.method$Entity$getId(player)) return; - byte eventId = NetworkReflections.field$ClientboundEntityEventPacket$eventId.getByte(packet); + byte eventId = (byte) NetworkReflections.methodHandle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet); if (eventId >= 24 && eventId <= 28) { CraftEngine.instance().fontManager().refreshEmojiSuggestions(user.uuid()); } - } catch (Exception e) { + } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ClientboundEntityEventPacket", e); } }; - public static final TriConsumer MOVE_POS_ENTITY = (user, event, packet) -> { - try { - int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { - event.setCancelled(true); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e); - } - }; - public static final TriConsumer MOVE_POS_AND_ROTATE_ENTITY = (user, event, packet) -> { try { int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); @@ -2310,4 +2350,15 @@ public class PacketConsumers { } }; + public static final TriConsumer MOVE_POS_ENTITY = (user, event, packet) -> { + try { + int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null) { + handler.handleMove(user, event, packet); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e); + } + }; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java index 00d588a66..678e06f1a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java @@ -52,7 +52,11 @@ public interface PacketIds { int clientboundSetPlayerInventoryPacket(); + int clientboundBlockEventPacket(); + int serverboundContainerClickPacket(); int serverboundSetCreativeModeSlotPacket(); + + int serverboundInteractPacket(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java index 52359827c..df172d479 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java @@ -2,8 +2,10 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.EntityDataUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; @@ -27,6 +29,11 @@ public class CommonItemPacketHandler implements EntityPacketHandler { int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); if (entityDataId == EntityDataUtils.ITEM_DATA_ID) { Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + // TODO 检查为什么会导致问题,难道是其他插件乱发entity id? + if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) { + CraftEngine.instance().logger().warn("Invalid item data for entity " + id); + continue; + } ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); Optional optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user); if (optional.isPresent()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurnitureCollisionPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurnitureCollisionPacketHandler.java index 70121b19b..63332219f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurnitureCollisionPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurnitureCollisionPacketHandler.java @@ -11,4 +11,9 @@ public class FurnitureCollisionPacketHandler implements EntityPacketHandler { public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) { event.setCancelled(true); } -} + + @Override + public void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) { + event.setCancelled(true); + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java index f9f0134a6..0a60cfc3a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/FurniturePacketHandler.java @@ -24,4 +24,9 @@ public class FurniturePacketHandler implements EntityPacketHandler { public void handleSyncEntityPosition(NetWorkUser user, NMSPacketEvent event, Object packet) { event.setCancelled(true); } + + @Override + public void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) { + event.setCancelled(true); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java index c936562f8..3d671ff0a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java @@ -81,7 +81,7 @@ public class ProjectilePacketHandler implements EntityPacketHandler { buf.writeVarInt(event.packetID()); buf.writeVarInt(this.entityId); buf.writeUUID(uuid); - buf.writeVarInt(MEntityTypes.instance$EntityType$ITEM_DISPLAY$registryId); + buf.writeVarInt(MEntityTypes.ITEM_DISPLAY$registryId); buf.writeDouble(x); buf.writeDouble(y); buf.writeDouble(z); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java index 97271778a..d9ff6e609 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java @@ -139,4 +139,14 @@ public class PacketIds1_20 implements PacketIds { public int serverboundSetCreativeModeSlotPacket() { return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket); } + + @Override + public int clientboundBlockEventPacket() { + return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundBlockEventPacket); + } + + @Override + public int serverboundInteractPacket() { + return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundInteractPacket); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java index bb29be78b..03d66538a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java @@ -129,6 +129,11 @@ public class PacketIds1_20_5 implements PacketIds { return PacketIdFinder.clientboundByName("minecraft:set_player_inventory"); } + @Override + public int clientboundBlockEventPacket() { + return PacketIdFinder.clientboundByName("minecraft:block_event"); + } + @Override public int serverboundContainerClickPacket() { return PacketIdFinder.serverboundByName("minecraft:container_click"); @@ -138,4 +143,9 @@ public class PacketIds1_20_5 implements PacketIds { public int serverboundSetCreativeModeSlotPacket() { return PacketIdFinder.serverboundByName("minecraft:set_creative_mode_slot"); } + + @Override + public int serverboundInteractPacket() { + return PacketIdFinder.serverboundByName("minecraft:interact"); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index a89afddbf..af3fd9355 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -5,12 +5,15 @@ import com.google.gson.JsonElement; import com.mojang.serialization.DynamicOps; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelFuture; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import java.io.BufferedReader; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; import java.lang.invoke.VarHandle; import java.lang.reflect.*; import java.util.*; @@ -1353,10 +1356,6 @@ public final class CoreReflections { ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getBlockSupportShape", "b_"}, clazz$BlockState, clazz$BlockGetter, CoreReflections.clazz$BlockPos) ); - public static final Method method$LevelAccessor$scheduleTick = requireNonNull( - ReflectionUtils.getMethod(clazz$LevelAccessor, void.class, CoreReflections.clazz$BlockPos, clazz$Block, int.class) - ); - public static final Field field$BlockBehaviour$properties = requireNonNull( ReflectionUtils.getInstanceDeclaredField(clazz$BlockBehaviour, clazz$BlockBehaviour$Properties, 0) ); @@ -3265,4 +3264,48 @@ public final class CoreReflections { public static final Method method$Registry$asLookup = ReflectionUtils.getMethod( clazz$Registry, clazz$HolderLookup$RegistryLookup, new String[]{"asLookup", "p"} ); + + public static final Field field$ServerEntity$broadcast = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ServerEntity, Consumer.class, 0 + ) + ); + + public static final MethodHandle methodHandle$ServerEntity$broadcastSetter; + public static final MethodHandle methodHandle$ServerEntity$updateIntervalSetter; + public static final MethodHandle methodHandle$ServerPlayer$connectionGetter; + + static { + try { + methodHandle$ServerEntity$broadcastSetter = requireNonNull( + ReflectionUtils.unreflectSetter(field$ServerEntity$broadcast) + .asType(MethodType.methodType(void.class, Object.class, Consumer.class)) + ); + methodHandle$ServerEntity$updateIntervalSetter = requireNonNull( + ReflectionUtils.unreflectSetter(field$ServerEntity$updateInterval) + .asType(MethodType.methodType(void.class, Object.class, int.class)) + ); + methodHandle$ServerPlayer$connectionGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerPlayer$connection) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + } catch (IllegalAccessException e) { + throw new ReflectionInitException("Failed to initialize reflection", e); + } + } + + public static final Class clazz$BaseFireBlock = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.level.block.BlockFireAbstract", + "world.level.block.BaseFireBlock" + ) + ); + + public static final Method method$BaseFireBlock$canBePlacedAt = requireNonNull( + ReflectionUtils.getStaticMethod(clazz$BaseFireBlock, boolean.class, clazz$Level, clazz$BlockPos, clazz$Direction) + ); + + public static final Field field$FireBlock$igniteOdds = requireNonNull( + ReflectionUtils.getDeclaredField(clazz$FireBlock, Object2IntMap.class, 0) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java index 6687be290..77a631de0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java @@ -16,6 +16,8 @@ public final class MBlocks { public static final Object ICE; public static final Object SHORT_GRASS; public static final Object SHORT_GRASS$defaultState; + public static final Object SHULKER_BOX; + public static final Object COMPOSTER; private static Object getById(String id) throws ReflectiveOperationException { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -33,6 +35,8 @@ public final class MBlocks { ICE = getById("ice"); SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass"); SHORT_GRASS$defaultState = CoreReflections.method$Block$defaultBlockState.invoke(SHORT_GRASS); + SHULKER_BOX = getById("shulker_box"); + COMPOSTER = getById("composter"); } catch (ReflectiveOperationException e) { throw new ReflectionInitException("Failed to init Blocks", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java index ba09983a0..d28c6581b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntityTypes.java @@ -7,50 +7,50 @@ import net.momirealms.craftengine.core.util.VersionHelper; public final class MEntityTypes { private MEntityTypes() {} - public static final Object instance$EntityType$TEXT_DISPLAY; - public static final int instance$EntityType$TEXT_DISPLAY$registryId; - public static final Object instance$EntityType$ITEM_DISPLAY; - public static final int instance$EntityType$ITEM_DISPLAY$registryId; - public static final Object instance$EntityType$BLOCK_DISPLAY; - public static final int instance$EntityType$BLOCK_DISPLAY$registryId; - public static final Object instance$EntityType$ARMOR_STAND; - public static final int instance$EntityType$ARMOR_STAND$registryId; - public static final Object instance$EntityType$FALLING_BLOCK; - public static final int instance$EntityType$FALLING_BLOCK$registryId; - public static final Object instance$EntityType$INTERACTION; - public static final int instance$EntityType$INTERACTION$registryId; - public static final Object instance$EntityType$SHULKER; - public static final int instance$EntityType$SHULKER$registryId; - public static final Object instance$EntityType$OAK_BOAT; - public static final int instance$EntityType$OAK_BOAT$registryId; - public static final Object instance$EntityType$TRIDENT; - public static final int instance$EntityType$TRIDENT$registryId; - public static final Object instance$EntityType$SNOWBALL; - public static final int instance$EntityType$SNOWBALL$registryId; - public static final Object instance$EntityType$FIREBALL; - public static final int instance$EntityType$FIREBALL$registryId; - public static final Object instance$EntityType$EYE_OF_ENDER; - public static final int instance$EntityType$EYE_OF_ENDER$registryId; - public static final Object instance$EntityType$FIREWORK_ROCKET; - public static final int instance$EntityType$FIREWORK_ROCKET$registryId; - public static final Object instance$EntityType$ITEM; - public static final int instance$EntityType$ITEM$registryId; - public static final Object instance$EntityType$ITEM_FRAME; - public static final int instance$EntityType$ITEM_FRAME$registryId; - public static final Object instance$EntityType$GLOW_ITEM_FRAME; - public static final int instance$EntityType$GLOW_ITEM_FRAME$registryId; - public static final Object instance$EntityType$OMINOUS_ITEM_SPAWNER; - public static final int instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId; - public static final Object instance$EntityType$SMALL_FIREBALL; - public static final int instance$EntityType$SMALL_FIREBALL$registryId; - public static final Object instance$EntityType$EGG; - public static final int instance$EntityType$EGG$registryId; - public static final Object instance$EntityType$ENDER_PEARL; - public static final int instance$EntityType$ENDER_PEARL$registryId; - public static final Object instance$EntityType$EXPERIENCE_BOTTLE; - public static final int instance$EntityType$EXPERIENCE_BOTTLE$registryId; - public static final Object instance$EntityType$POTION; - public static final int instance$EntityType$POTION$registryId; + public static final Object TEXT_DISPLAY; + public static final int TEXT_DISPLAY$registryId; + public static final Object ITEM_DISPLAY; + public static final int ITEM_DISPLAY$registryId; + public static final Object BLOCK_DISPLAY; + public static final int BLOCK_DISPLAY$registryId; + public static final Object ARMOR_STAND; + public static final int ARMOR_STAND$registryId; + public static final Object FALLING_BLOCK; + public static final int FALLING_BLOCK$registryId; + public static final Object INTERACTION; + public static final int INTERACTION$registryId; + public static final Object SHULKER; + public static final int SHULKER$registryId; + public static final Object OAK_BOAT; + public static final int OAK_BOAT$registryId; + public static final Object TRIDENT; + public static final int TRIDENT$registryId; + public static final Object SNOWBALL; + public static final int SNOWBALL$registryId; + public static final Object FIREBALL; + public static final int FIREBALL$registryId; + public static final Object EYE_OF_ENDER; + public static final int EYE_OF_ENDER$registryId; + public static final Object FIREWORK_ROCKET; + public static final int FIREWORK_ROCKET$registryId; + public static final Object ITEM; + public static final int ITEM$registryId; + public static final Object ITEM_FRAME; + public static final int ITEM_FRAME$registryId; + public static final Object GLOW_ITEM_FRAME; + public static final int GLOW_ITEM_FRAME$registryId; + public static final Object OMINOUS_ITEM_SPAWNER; + public static final int OMINOUS_ITEM_SPAWNER$registryId; + public static final Object SMALL_FIREBALL; + public static final int SMALL_FIREBALL$registryId; + public static final Object EGG; + public static final int EGG$registryId; + public static final Object ENDER_PEARL; + public static final int ENDER_PEARL$registryId; + public static final Object EXPERIENCE_BOTTLE; + public static final int EXPERIENCE_BOTTLE$registryId; + public static final Object POTION; + public static final int POTION$registryId; private static Object getById(String id) throws ReflectiveOperationException { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -64,50 +64,50 @@ public final class MEntityTypes { static { try { - instance$EntityType$TEXT_DISPLAY = getById("text_display"); - instance$EntityType$TEXT_DISPLAY$registryId = getRegistryId(instance$EntityType$TEXT_DISPLAY); - instance$EntityType$ITEM_DISPLAY = getById("item_display"); - instance$EntityType$ITEM_DISPLAY$registryId = getRegistryId(instance$EntityType$ITEM_DISPLAY); - instance$EntityType$BLOCK_DISPLAY = getById("block_display"); - instance$EntityType$BLOCK_DISPLAY$registryId = getRegistryId(instance$EntityType$BLOCK_DISPLAY); - instance$EntityType$FALLING_BLOCK = getById("falling_block"); - instance$EntityType$FALLING_BLOCK$registryId = getRegistryId(instance$EntityType$FALLING_BLOCK); - instance$EntityType$INTERACTION = getById("interaction"); - instance$EntityType$INTERACTION$registryId = getRegistryId(instance$EntityType$INTERACTION); - instance$EntityType$SHULKER = getById("shulker"); - instance$EntityType$SHULKER$registryId = getRegistryId(instance$EntityType$SHULKER); - instance$EntityType$ARMOR_STAND = getById("armor_stand"); - instance$EntityType$ARMOR_STAND$registryId = getRegistryId(instance$EntityType$ARMOR_STAND); - instance$EntityType$OAK_BOAT = getById(VersionHelper.isOrAbove1_21_2() ? "oak_boat" : "boat"); - instance$EntityType$OAK_BOAT$registryId = getRegistryId(instance$EntityType$OAK_BOAT); - instance$EntityType$TRIDENT = getById("trident"); - instance$EntityType$TRIDENT$registryId = getRegistryId(instance$EntityType$TRIDENT); - instance$EntityType$SNOWBALL = getById("snowball"); - instance$EntityType$SNOWBALL$registryId = getRegistryId(instance$EntityType$SNOWBALL); - instance$EntityType$FIREBALL = getById("fireball"); - instance$EntityType$FIREBALL$registryId = getRegistryId(instance$EntityType$FIREBALL); - instance$EntityType$EYE_OF_ENDER = getById("eye_of_ender"); - instance$EntityType$EYE_OF_ENDER$registryId = getRegistryId(instance$EntityType$EYE_OF_ENDER); - instance$EntityType$FIREWORK_ROCKET = getById("firework_rocket"); - instance$EntityType$FIREWORK_ROCKET$registryId = getRegistryId(instance$EntityType$FIREWORK_ROCKET); - instance$EntityType$ITEM = getById("item"); - instance$EntityType$ITEM$registryId = getRegistryId(instance$EntityType$ITEM); - instance$EntityType$ITEM_FRAME = getById("item_frame"); - instance$EntityType$ITEM_FRAME$registryId = getRegistryId(instance$EntityType$ITEM_FRAME); - instance$EntityType$GLOW_ITEM_FRAME = getById("glow_item_frame"); - instance$EntityType$GLOW_ITEM_FRAME$registryId = getRegistryId(instance$EntityType$GLOW_ITEM_FRAME); - instance$EntityType$SMALL_FIREBALL = getById("small_fireball"); - instance$EntityType$SMALL_FIREBALL$registryId = getRegistryId(instance$EntityType$SMALL_FIREBALL); - instance$EntityType$EGG = getById("egg"); - instance$EntityType$EGG$registryId = getRegistryId(instance$EntityType$EGG); - instance$EntityType$ENDER_PEARL = getById("ender_pearl"); - instance$EntityType$ENDER_PEARL$registryId = getRegistryId(instance$EntityType$ENDER_PEARL); - instance$EntityType$EXPERIENCE_BOTTLE = getById("experience_bottle"); - instance$EntityType$EXPERIENCE_BOTTLE$registryId = getRegistryId(instance$EntityType$EXPERIENCE_BOTTLE); - instance$EntityType$POTION = getById("potion"); - instance$EntityType$POTION$registryId = getRegistryId(instance$EntityType$POTION); - instance$EntityType$OMINOUS_ITEM_SPAWNER = VersionHelper.isOrAbove1_20_5() ? getById("ominous_item_spawner") : null; - instance$EntityType$OMINOUS_ITEM_SPAWNER$registryId = getRegistryId(instance$EntityType$OMINOUS_ITEM_SPAWNER); + TEXT_DISPLAY = getById("text_display"); + TEXT_DISPLAY$registryId = getRegistryId(TEXT_DISPLAY); + ITEM_DISPLAY = getById("item_display"); + ITEM_DISPLAY$registryId = getRegistryId(ITEM_DISPLAY); + BLOCK_DISPLAY = getById("block_display"); + BLOCK_DISPLAY$registryId = getRegistryId(BLOCK_DISPLAY); + FALLING_BLOCK = getById("falling_block"); + FALLING_BLOCK$registryId = getRegistryId(FALLING_BLOCK); + INTERACTION = getById("interaction"); + INTERACTION$registryId = getRegistryId(INTERACTION); + SHULKER = getById("shulker"); + SHULKER$registryId = getRegistryId(SHULKER); + ARMOR_STAND = getById("armor_stand"); + ARMOR_STAND$registryId = getRegistryId(ARMOR_STAND); + OAK_BOAT = getById(VersionHelper.isOrAbove1_21_2() ? "oak_boat" : "boat"); + OAK_BOAT$registryId = getRegistryId(OAK_BOAT); + TRIDENT = getById("trident"); + TRIDENT$registryId = getRegistryId(TRIDENT); + SNOWBALL = getById("snowball"); + SNOWBALL$registryId = getRegistryId(SNOWBALL); + FIREBALL = getById("fireball"); + FIREBALL$registryId = getRegistryId(FIREBALL); + EYE_OF_ENDER = getById("eye_of_ender"); + EYE_OF_ENDER$registryId = getRegistryId(EYE_OF_ENDER); + FIREWORK_ROCKET = getById("firework_rocket"); + FIREWORK_ROCKET$registryId = getRegistryId(FIREWORK_ROCKET); + ITEM = getById("item"); + ITEM$registryId = getRegistryId(ITEM); + ITEM_FRAME = getById("item_frame"); + ITEM_FRAME$registryId = getRegistryId(ITEM_FRAME); + GLOW_ITEM_FRAME = getById("glow_item_frame"); + GLOW_ITEM_FRAME$registryId = getRegistryId(GLOW_ITEM_FRAME); + SMALL_FIREBALL = getById("small_fireball"); + SMALL_FIREBALL$registryId = getRegistryId(SMALL_FIREBALL); + EGG = getById("egg"); + EGG$registryId = getRegistryId(EGG); + ENDER_PEARL = getById("ender_pearl"); + ENDER_PEARL$registryId = getRegistryId(ENDER_PEARL); + EXPERIENCE_BOTTLE = getById("experience_bottle"); + EXPERIENCE_BOTTLE$registryId = getRegistryId(EXPERIENCE_BOTTLE); + POTION = getById("potion"); + POTION$registryId = getRegistryId(POTION); + OMINOUS_ITEM_SPAWNER = VersionHelper.isOrAbove1_20_5() ? getById("ominous_item_spawner") : null; + OMINOUS_ITEM_SPAWNER$registryId = getRegistryId(OMINOUS_ITEM_SPAWNER); } catch (ReflectiveOperationException e) { throw new ReflectionInitException("Failed to init EntityTypes", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRegistries.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRegistries.java index 04a754e1b..244d26904 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRegistries.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRegistries.java @@ -10,21 +10,23 @@ import java.lang.reflect.Type; import static java.util.Objects.requireNonNull; public final class MRegistries { - public static final Object instance$Registries$BLOCK; - public static final Object instance$Registries$ITEM; - public static final Object instance$Registries$ATTRIBUTE; - public static final Object instance$Registries$BIOME; - public static final Object instance$Registries$MOB_EFFECT; - public static final Object instance$Registries$SOUND_EVENT; - public static final Object instance$Registries$PARTICLE_TYPE; - public static final Object instance$Registries$ENTITY_TYPE; - public static final Object instance$Registries$FLUID; - public static final Object instance$Registries$RECIPE_TYPE; - public static final Object instance$Registries$DIMENSION_TYPE; - public static final Object instance$Registries$CONFIGURED_FEATURE; - public static final Object instance$Registries$PLACED_FEATURE; + public static final Object BLOCK; + public static final Object ITEM; + public static final Object ATTRIBUTE; + public static final Object BIOME; + public static final Object MOB_EFFECT; + public static final Object SOUND_EVENT; + public static final Object PARTICLE_TYPE; + public static final Object ENTITY_TYPE; + public static final Object FLUID; + public static final Object RECIPE_TYPE; + public static final Object DIMENSION_TYPE; + public static final Object CONFIGURED_FEATURE; + public static final Object PLACED_FEATURE; @Nullable // 1.21+ - public static final Object instance$Registries$JUKEBOX_SONG; + public static final Object JUKEBOX_SONG; + @Nullable // 1.21+ + public static final Object RECIPE; static { Field[] fields = CoreReflections.clazz$Registries.getDeclaredFields(); @@ -43,6 +45,7 @@ public final class MRegistries { Object registries$ConfiguredFeature = null; Object registries$PlacedFeature = null; Object registries$JukeboxSong = null; + Object registries$Recipe = null; for (Field field : fields) { Type fieldType = field.getGenericType(); if (fieldType instanceof ParameterizedType paramType) { @@ -60,6 +63,8 @@ public final class MRegistries { registries$RecipeType = field.get(null); } else if (rawType == CoreReflections.clazz$ConfiguredFeature) { registries$ConfiguredFeature = field.get(null); + } else if (rawType == CoreReflections.clazz$Recipe) { + registries$Recipe = field.get(null); } } else { if (type == CoreReflections.clazz$Block) { @@ -88,20 +93,21 @@ public final class MRegistries { } } } - instance$Registries$BLOCK = requireNonNull(registries$Block); - instance$Registries$ITEM = requireNonNull(registries$Item); - instance$Registries$ATTRIBUTE = requireNonNull(registries$Attribute); - instance$Registries$BIOME = requireNonNull(registries$Biome); - instance$Registries$MOB_EFFECT = requireNonNull(registries$MobEffect); - instance$Registries$SOUND_EVENT = requireNonNull(registries$SoundEvent); - instance$Registries$DIMENSION_TYPE = requireNonNull(registries$DimensionType); - instance$Registries$PARTICLE_TYPE = requireNonNull(registries$ParticleType); - instance$Registries$ENTITY_TYPE = requireNonNull(registries$EntityType); - instance$Registries$FLUID = requireNonNull(registries$Fluid); - instance$Registries$RECIPE_TYPE = requireNonNull(registries$RecipeType); - instance$Registries$CONFIGURED_FEATURE = requireNonNull(registries$ConfiguredFeature); - instance$Registries$PLACED_FEATURE = requireNonNull(registries$PlacedFeature); - instance$Registries$JUKEBOX_SONG = registries$JukeboxSong; + BLOCK = requireNonNull(registries$Block); + ITEM = requireNonNull(registries$Item); + ATTRIBUTE = requireNonNull(registries$Attribute); + BIOME = requireNonNull(registries$Biome); + MOB_EFFECT = requireNonNull(registries$MobEffect); + SOUND_EVENT = requireNonNull(registries$SoundEvent); + DIMENSION_TYPE = requireNonNull(registries$DimensionType); + PARTICLE_TYPE = requireNonNull(registries$ParticleType); + ENTITY_TYPE = requireNonNull(registries$EntityType); + FLUID = requireNonNull(registries$Fluid); + RECIPE_TYPE = requireNonNull(registries$RecipeType); + CONFIGURED_FEATURE = requireNonNull(registries$ConfiguredFeature); + PLACED_FEATURE = requireNonNull(registries$PlacedFeature); + JUKEBOX_SONG = registries$JukeboxSong; + RECIPE = registries$Recipe; } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRegistryOps.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRegistryOps.java index 9ad05cd9d..6af862ac3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRegistryOps.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRegistryOps.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.sparrow.nbt.codec.LegacyJavaOps; import net.momirealms.sparrow.nbt.codec.LegacyNBTOps; import net.momirealms.sparrow.nbt.codec.NBTOps; @@ -34,8 +35,12 @@ public class MRegistryOps { static { try { if (clazz$JavaOps != null) { + // 1.20.5+ Object javaOps = ReflectionUtils.getDeclaredField(clazz$JavaOps, clazz$JavaOps, 0).get(null); JAVA = (DynamicOps) CoreReflections.method$RegistryOps$create.invoke(null, javaOps, FastNMS.INSTANCE.registryAccess()); + } else if (!VersionHelper.isOrAbove1_20_5()) { + // 1.20.1-1.20.4 + JAVA = (DynamicOps) CoreReflections.method$RegistryOps$create.invoke(null, LegacyJavaOps.INSTANCE, FastNMS.INSTANCE.registryAccess()); } else { JAVA = null; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index c031447eb..2b0498e8c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1,10 +1,13 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import io.netty.buffer.ByteBuf; +import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -968,7 +971,7 @@ public final class NetworkReflections { ); public static final Field field$ServerboundEditBookPacket$slot = requireNonNull( - ReflectionUtils.getDeclaredField(clazz$ServerboundEditBookPacket, int.class, 0) + ReflectionUtils.getDeclaredField(clazz$ServerboundEditBookPacket, int.class, VersionHelper.isOrAbove1_20_5() ? 0 : 4) ); public static final Field field$ServerboundEditBookPacket$pages = requireNonNull( @@ -1293,4 +1296,177 @@ public final class NetworkReflections { public static final Constructor constructor$ClientboundTickingStatePacket = Optional.ofNullable(clazz$ClientboundTickingStatePacket) .map(it -> ReflectionUtils.getConstructor(it, float.class, boolean.class)) .orElse(null); + + public static final Class clazz$ClientboundBlockEventPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayOutBlockAction", + "network.protocol.game.ClientboundBlockEventPacket" + ) + ); + + public static final MethodHandle methodHandle$ServerboundRenameItemPacket$nameGetter; + public static final MethodHandle methodHandle$ServerboundRenameItemPacket$nameSetter; + public static final MethodHandle methodHandle$ServerboundHelloPacket$nameGetter; + public static final MethodHandle methodHandle$ServerboundHelloPacket$uuidGetter; + public static final MethodHandle methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter; + public static final MethodHandle methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter; + public static final MethodHandle methodHandle$ServerboundInteractPacket$actionGetter; + public static final MethodHandle methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter; + public static final MethodHandle methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter; + public static final MethodHandle methodHandle$ServerboundSignUpdatePacket$linesGetter; + public static final MethodHandle methodHandle$ServerboundEditBookPacket$pagesGetter; + public static final MethodHandle methodHandle$ServerboundEditBookPacket$titleGetter; + public static final MethodHandle methodHandle$ServerboundEditBookPacket$slotGetter; + public static final MethodHandle methodHandle$ServerboundResourcePackPacket$actionGetter; + public static final MethodHandle methodHandle$ClientboundEntityEventPacket$entityIdGetter; + public static final MethodHandle methodHandle$ClientboundEntityEventPacket$eventIdGetter; + public static final MethodHandle methodHandle$ClientIntentionPacket$protocolVersionGetter; + public static final MethodHandle methodHandle$ClientboundRespawnPacket$dimensionGetter; + public static final MethodHandle methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter; + public static final MethodHandle methodHandle$CommonPlayerSpawnInfo$dimensionGetter; + public static final MethodHandle methodHandle$ClientboundLoginPacket$dimensionGetter; + public static final MethodHandle methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter; + public static final MethodHandle methodHandle$ServerboundPickItemFromBlockPacket$posGetter; + public static final MethodHandle methodHandle$ServerboundPickItemFromEntityPacket$idGetter; + public static final MethodHandle methodHandle$ServerboundCustomPayloadPacket$payloadGetter; + + static { + try { + methodHandle$ServerboundRenameItemPacket$nameGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundRenameItemPacket$name) + .asType(MethodType.methodType(String.class, Object.class)) + ); + methodHandle$ServerboundRenameItemPacket$nameSetter = requireNonNull( + ReflectionUtils.unreflectSetter(field$ServerboundRenameItemPacket$name) + .asType(MethodType.methodType(void.class, Object.class, String.class)) + ); + methodHandle$ServerboundHelloPacket$nameGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundHelloPacket$name) + .asType(MethodType.methodType(String.class, Object.class)) + ); + methodHandle$ServerboundHelloPacket$uuidGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundHelloPacket$uuid) + .asType(MethodType.methodType(VersionHelper.isOrAbove1_20_2() ? UUID.class : Optional.class, Object.class)) + ); + methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundSetCreativeModeSlotPacket$itemStack) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundSetCreativeModeSlotPacket$slotNum) + .asType(MethodType.methodType(VersionHelper.isOrAbove1_20_5() ? short.class : int.class, Object.class)) + ); + methodHandle$ServerboundInteractPacket$actionGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$action) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$handGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$InteractionAtLocationAction$hand) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + methodHandle$ServerboundInteractPacket$InteractionAtLocationAction$locationGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundInteractPacket$InteractionAtLocationAction$location) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + methodHandle$ServerboundSignUpdatePacket$linesGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundSignUpdatePacket$lines) + .asType(MethodType.methodType(String[].class, Object.class)) + ); + methodHandle$ServerboundEditBookPacket$pagesGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$pages) + .asType(MethodType.methodType(List.class, Object.class)) + ); + methodHandle$ServerboundEditBookPacket$titleGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$title) + .asType(MethodType.methodType(Optional.class, Object.class)) + ); + methodHandle$ServerboundEditBookPacket$slotGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundEditBookPacket$slot) + .asType(MethodType.methodType(int.class, Object.class)) + ); + methodHandle$ServerboundResourcePackPacket$actionGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundResourcePackPacket$action) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + methodHandle$ClientboundEntityEventPacket$entityIdGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$entityId) + .asType(MethodType.methodType(int.class, Object.class)) + ); + methodHandle$ClientboundEntityEventPacket$eventIdGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ClientboundEntityEventPacket$eventId) + .asType(MethodType.methodType(byte.class, Object.class)) + ); + methodHandle$ClientIntentionPacket$protocolVersionGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ClientIntentionPacket$protocolVersion) + .asType(MethodType.methodType(int.class, Object.class)) + ); + if (field$ServerboundCustomPayloadPacket$payload != null) { + methodHandle$ServerboundCustomPayloadPacket$payloadGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundCustomPayloadPacket$payload) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + } else { + methodHandle$ServerboundCustomPayloadPacket$payloadGetter = null; + } + if (field$ServerboundPickItemFromEntityPacket$id != null) { + methodHandle$ServerboundPickItemFromEntityPacket$idGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundPickItemFromEntityPacket$id) + .asType(MethodType.methodType(int.class, Object.class)) + ); + } else { + methodHandle$ServerboundPickItemFromEntityPacket$idGetter = null; + } + if (field$ServerboundPickItemFromBlockPacket$pos != null) { + methodHandle$ServerboundPickItemFromBlockPacket$posGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ServerboundPickItemFromBlockPacket$pos) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + } else { + methodHandle$ServerboundPickItemFromBlockPacket$posGetter = null; + } + if (field$ClientboundLoginPacket$commonPlayerSpawnInfo != null) { + methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ClientboundLoginPacket$commonPlayerSpawnInfo) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + } else { + methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter = null; + } + if (field$ClientboundLoginPacket$dimension != null) { + methodHandle$ClientboundLoginPacket$dimensionGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ClientboundLoginPacket$dimension) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + } else { + methodHandle$ClientboundLoginPacket$dimensionGetter = null; + } + if (field$CommonPlayerSpawnInfo$dimension != null) { + methodHandle$CommonPlayerSpawnInfo$dimensionGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$CommonPlayerSpawnInfo$dimension) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + } else { + methodHandle$CommonPlayerSpawnInfo$dimensionGetter = null; + } + if (field$ClientboundRespawnPacket$commonPlayerSpawnInfo != null) { + methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ClientboundRespawnPacket$commonPlayerSpawnInfo) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + } else { + methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter = null; + } + if (field$ClientboundRespawnPacket$dimension != null) { + methodHandle$ClientboundRespawnPacket$dimensionGetter = requireNonNull( + ReflectionUtils.unreflectGetter(field$ClientboundRespawnPacket$dimension) + .asType(MethodType.methodType(Object.class, Object.class)) + ); + } else { + methodHandle$ClientboundRespawnPacket$dimensionGetter = null; + } + } catch (Throwable e) { + throw new ReflectionInitException("Failed to initialize reflection", e); + } + } + } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index b1ce6b3ae..8adcef88f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -30,10 +30,12 @@ import net.momirealms.craftengine.core.plugin.context.CooldownData; import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.plugin.network.ProtocolVersion; +import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.Position; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldEvents; import org.bukkit.*; @@ -138,17 +140,17 @@ public class BukkitServerPlayer extends Player { @Override public Channel nettyChannel() { - return channel; + return this.channel; } @Override public CraftEngine plugin() { - return plugin; + return this.plugin; } @Override public boolean isMiningBlock() { - return destroyPos != null; + return this.destroyPos != null; } public void setDestroyedState(Object destroyedState) { @@ -221,8 +223,8 @@ public class BukkitServerPlayer extends Player { @Override public boolean updateLastSuccessfulInteractionTick(int tick) { - if (lastSuccessfulInteraction != tick) { - lastSuccessfulInteraction = tick; + if (this.lastSuccessfulInteraction != tick) { + this.lastSuccessfulInteraction = tick; return true; } else { return false; @@ -231,7 +233,7 @@ public class BukkitServerPlayer extends Player { @Override public int lastSuccessfulInteractionTick() { - return lastSuccessfulInteraction; + return this.lastSuccessfulInteraction; } @Override @@ -283,8 +285,13 @@ public class BukkitServerPlayer extends Player { } @Override - public void playSound(Key sound, float volume, float pitch) { - platformPlayer().playSound(platformPlayer(), sound.toString(), SoundCategory.MASTER, volume, pitch); + public void playSound(Key sound, SoundSource source, float volume, float pitch) { + platformPlayer().playSound(platformPlayer(), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); + } + + @Override + public void playSound(Key sound, BlockPos blockPos, SoundSource source, float volume, float pitch) { + platformPlayer().playSound(new Location(null, blockPos.x() + 0.5, blockPos.y() + 0.5, blockPos.z() + 0.5), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); } @Override @@ -535,8 +542,10 @@ public class BukkitServerPlayer extends Player { public void abortMiningBlock() { this.swingHandAck = false; this.miningProgress = 0; - if (this.destroyPos != null) { - this.broadcastDestroyProgress(platformPlayer(), this.destroyPos, LocationUtils.toBlockPos(this.destroyPos), -1); + BlockPos pos = this.destroyPos; + if (pos != null && this.isDestroyingCustomBlock) { + // 只纠正自定义方块的 + this.broadcastDestroyProgress(platformPlayer(), pos, LocationUtils.toBlockPos(pos), -1); } } @@ -558,6 +567,8 @@ public class BukkitServerPlayer extends Player { int currentTick = gameTicks(); // optimize break speed, otherwise it would be too fast if (currentTick - this.lastSuccessfulBreak <= 5) return; + Object destroyedState = this.destroyedState; + if (destroyedState == null) return; try { org.bukkit.entity.Player player = platformPlayer(); double range = getCachedInteractionRange(); @@ -575,7 +586,7 @@ public class BukkitServerPlayer extends Player { // send hit sound if the sound is removed if (currentTick - this.lastHitBlockTime > 3) { - Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(this.destroyedState); + Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(destroyedState); Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(blockOwner); Object soundEvent = CoreReflections.field$SoundType$hitSound.get(soundType); Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); @@ -601,8 +612,8 @@ public class BukkitServerPlayer extends Player { } } - float progressToAdd = getDestroyProgress(this.destroyedState, hitPos); - int id = BlockStateUtils.blockStateToId(this.destroyedState); + float progressToAdd = getDestroyProgress(destroyedState, hitPos); + int id = BlockStateUtils.blockStateToId(destroyedState); ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(id); // double check custom block if (customState != null && !customState.isEmpty()) { @@ -612,13 +623,13 @@ public class BukkitServerPlayer extends Player { // it's correct on plugin side if (blockSettings.isCorrectTool(item.id())) { // but not on serverside - if (!FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), this.destroyedState)) { + if (!FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), destroyedState)) { // we fix the speed progressToAdd = progressToAdd * (10f / 3f); } } else { // not a correct tool on plugin side and not a correct tool on serverside - if (!blockSettings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), this.destroyedState)) { + if (!blockSettings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(item.getLiteralObject(), destroyedState)) { progressToAdd = progressToAdd * (10f / 3f) * blockSettings.incorrectToolSpeed(); } } @@ -681,7 +692,7 @@ public class BukkitServerPlayer extends Player { double d1 = (double) hitPos.y() - otherLocation.getY(); double d2 = (double) hitPos.z() - otherLocation.getZ(); if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) { - this.plugin.networkManager().sendPacket(this.plugin.adapt(other), packet); + FastNMS.INSTANCE.sendPacket(FastNMS.INSTANCE.field$Player$connection$connection(FastNMS.INSTANCE.method$CraftPlayer$getHandle(other)), packet); } } } @@ -699,16 +710,20 @@ public class BukkitServerPlayer extends Player { public void setIsDestroyingBlock(boolean is, boolean custom) { this.miningProgress = 0; this.isDestroyingBlock = is; - this.isDestroyingCustomBlock = custom && is; if (is) { this.swingHandAck = true; + this.isDestroyingCustomBlock = custom; } else { this.swingHandAck = false; this.destroyedState = null; if (this.destroyPos != null) { - this.broadcastDestroyProgress(platformPlayer(), this.destroyPos, LocationUtils.toBlockPos(this.destroyPos), -1); + // 只纠正自定义方块的 + if (this.isDestroyingCustomBlock) { + this.broadcastDestroyProgress(platformPlayer(), this.destroyPos, LocationUtils.toBlockPos(this.destroyPos), -1); + } this.destroyPos = null; } + this.isDestroyingCustomBlock = false; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java index 50dfb6b68..4500128e3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/sound/BukkitSoundManager.java @@ -26,7 +26,7 @@ public class BukkitSoundManager extends AbstractSoundManager { protected void registerSongs(Map songs) { if (songs.isEmpty()) return; try { - Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.instance$Registries$JUKEBOX_SONG);; + Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.JUKEBOX_SONG);; unfreezeRegistry(registry); for (Map.Entry entry : songs.entrySet()) { Key id = entry.getKey(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java index c2eb45f8c..c0079d0e9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java @@ -2,8 +2,10 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.core.block.*; @@ -22,18 +24,26 @@ import org.jetbrains.annotations.Nullable; import java.util.IdentityHashMap; import java.util.List; +import java.util.Map; import java.util.Optional; public class BlockStateUtils { public static final IdentityHashMap CLIENT_SIDE_NOTE_BLOCKS = new IdentityHashMap<>(); private static int vanillaStateSize; private static boolean hasInit; + public static Map IGNITE_ODDS; + @SuppressWarnings("unchecked") public static void init(int size) { if (hasInit) { throw new IllegalStateException("BlockStateUtils has already been initialized"); } vanillaStateSize = size; + try { + IGNITE_ODDS = (Map) CoreReflections.field$FireBlock$igniteOdds.get(MBlocks.FIRE); + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize instance$FireBlock$igniteOdds", e); + } hasInit = true; } @@ -248,4 +258,9 @@ public class BlockStateUtils { public static int vanillaStateSize() { return vanillaStateSize; } + + public static boolean isBurnable(Object state) { + Object blockOwner = getBlockOwner(state); + return IGNITE_ODDS.getOrDefault(blockOwner, 0) > 0; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java index 75728c940..a83a91c27 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockTags.java @@ -16,7 +16,7 @@ public class BlockTags { Object value = CACHE.get(key); if (value == null) { try { - value = CoreReflections.method$TagKey$create.invoke(null, MRegistries.instance$Registries$BLOCK, KeyUtils.toResourceLocation(key)); + value = CoreReflections.method$TagKey$create.invoke(null, MRegistries.BLOCK, KeyUtils.toResourceLocation(key)); CACHE.put(key, value); return value; } catch (Exception e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BukkitReflectionUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BukkitReflectionUtils.java index 2d3a32de5..b7d10e671 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BukkitReflectionUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BukkitReflectionUtils.java @@ -2,11 +2,8 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; -import org.bukkit.Bukkit; -import java.lang.reflect.Method; import java.util.List; -import java.util.Objects; import java.util.function.Function; public final class BukkitReflectionUtils { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DamageCauseUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DamageCauseUtils.java new file mode 100644 index 000000000..0f0c1be64 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DamageCauseUtils.java @@ -0,0 +1,85 @@ +package net.momirealms.craftengine.bukkit.util; + +import net.momirealms.craftengine.core.util.DamageSource; +import org.bukkit.event.entity.EntityDamageEvent; + +public class DamageCauseUtils { + + private DamageCauseUtils() {} + + public static EntityDamageEvent.DamageCause toBukkit(DamageSource cause) { + return switch (cause) { + case BLOCK_EXPLOSION -> EntityDamageEvent.DamageCause.BLOCK_EXPLOSION; + case CAMPFIRE -> EntityDamageEvent.DamageCause.CAMPFIRE; + case CONTACT -> EntityDamageEvent.DamageCause.CONTACT; + case CRAMMING -> EntityDamageEvent.DamageCause.CRAMMING; + case CUSTOM -> EntityDamageEvent.DamageCause.CUSTOM; + case DROWNING -> EntityDamageEvent.DamageCause.DROWNING; + case DRYOUT -> EntityDamageEvent.DamageCause.DRYOUT; + case ENTITY_ATTACK -> EntityDamageEvent.DamageCause.ENTITY_ATTACK; + case ENTITY_EXPLOSION -> EntityDamageEvent.DamageCause.ENTITY_EXPLOSION; + case ENTITY_SWEEP_ATTACK -> EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK; + case FALL -> EntityDamageEvent.DamageCause.FALL; + case FALLING_BLOCK -> EntityDamageEvent.DamageCause.FALLING_BLOCK; + case FIRE -> EntityDamageEvent.DamageCause.FIRE; + case FIRE_TICK -> EntityDamageEvent.DamageCause.FIRE_TICK; + case FLY_INTO_WALL -> EntityDamageEvent.DamageCause.FLY_INTO_WALL; + case FREEZE -> EntityDamageEvent.DamageCause.FREEZE; + case HOT_FLOOR -> EntityDamageEvent.DamageCause.HOT_FLOOR; + case KILL -> EntityDamageEvent.DamageCause.KILL; + case LAVA -> EntityDamageEvent.DamageCause.LAVA; + case LIGHTNING -> EntityDamageEvent.DamageCause.LIGHTNING; + case MAGIC -> EntityDamageEvent.DamageCause.MAGIC; + case MELTING -> EntityDamageEvent.DamageCause.MELTING; + case POISON -> EntityDamageEvent.DamageCause.POISON; + case PROJECTILE -> EntityDamageEvent.DamageCause.PROJECTILE; + case SONIC_BOOM -> EntityDamageEvent.DamageCause.SONIC_BOOM; + case STARVATION -> EntityDamageEvent.DamageCause.STARVATION; + case SUFFOCATION -> EntityDamageEvent.DamageCause.SUFFOCATION; + case SUICIDE -> EntityDamageEvent.DamageCause.SUICIDE; + case THORNS -> EntityDamageEvent.DamageCause.THORNS; + case VOID -> EntityDamageEvent.DamageCause.VOID; + case WITHER -> EntityDamageEvent.DamageCause.WITHER; + case WORLD_BORDER -> EntityDamageEvent.DamageCause.WORLD_BORDER; + default -> null; + }; + } + + public static DamageSource fromBukkit(EntityDamageEvent.DamageCause cause) { + return switch (cause) { + case BLOCK_EXPLOSION -> DamageSource.BLOCK_EXPLOSION; + case CAMPFIRE -> DamageSource.CAMPFIRE; + case CONTACT -> DamageSource.CONTACT; + case CRAMMING -> DamageSource.CRAMMING; + case CUSTOM -> DamageSource.CUSTOM; + case DROWNING -> DamageSource.DROWNING; + case DRYOUT -> DamageSource.DRYOUT; + case ENTITY_ATTACK -> DamageSource.ENTITY_ATTACK; + case ENTITY_EXPLOSION -> DamageSource.ENTITY_EXPLOSION; + case ENTITY_SWEEP_ATTACK -> DamageSource.ENTITY_SWEEP_ATTACK; + case FALL -> DamageSource.FALL; + case FALLING_BLOCK -> DamageSource.FALLING_BLOCK; + case FIRE -> DamageSource.FIRE; + case FIRE_TICK -> DamageSource.FIRE_TICK; + case FLY_INTO_WALL -> DamageSource.FLY_INTO_WALL; + case FREEZE -> DamageSource.FREEZE; + case HOT_FLOOR -> DamageSource.HOT_FLOOR; + case KILL -> DamageSource.KILL; + case LAVA -> DamageSource.LAVA; + case LIGHTNING -> DamageSource.LIGHTNING; + case MAGIC -> DamageSource.MAGIC; + case MELTING -> DamageSource.MELTING; + case POISON -> DamageSource.POISON; + case PROJECTILE -> DamageSource.PROJECTILE; + case SONIC_BOOM -> DamageSource.SONIC_BOOM; + case STARVATION -> DamageSource.STARVATION; + case SUFFOCATION -> DamageSource.SUFFOCATION; + case SUICIDE -> DamageSource.SUICIDE; + case THORNS -> DamageSource.THORNS; + case VOID -> DamageSource.VOID; + case WITHER -> DamageSource.WITHER; + case WORLD_BORDER -> DamageSource.WORLD_BORDER; + default -> null; + }; + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FeatureUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FeatureUtils.java index 800c203aa..e985bf7d6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FeatureUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/FeatureUtils.java @@ -10,7 +10,7 @@ public class FeatureUtils { public static Object createFeatureKey(Key id) { try { - return CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.instance$Registries$CONFIGURED_FEATURE, KeyUtils.toResourceLocation(id)); + return CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.CONFIGURED_FEATURE, KeyUtils.toResourceLocation(id)); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java index 32319db3d..345d00e01 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java @@ -92,6 +92,7 @@ public class InteractUtils { keyReference, item.getItem() ))) != null).isPresent(); }); + registerInteraction(BlockKeys.DECORATED_POT, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.HOPPER, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DISPENSER, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DROPPER, (player, item, blockState, result) -> true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java index fc87dbc53..2e972673e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java @@ -19,7 +19,7 @@ public class ItemTags { Object value = CACHE.get(key); if (value == null) { try { - value = CoreReflections.method$TagKey$create.invoke(null, MRegistries.instance$Registries$ITEM, KeyUtils.toResourceLocation(key)); + value = CoreReflections.method$TagKey$create.invoke(null, MRegistries.ITEM, KeyUtils.toResourceLocation(key)); CACHE.put(key, value); return value; } catch (Exception e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java index 39d85f954..3cb195fa0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java @@ -1,19 +1,19 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.core.plugin.config.Config; public class NoteBlockChainUpdateUtils { private NoteBlockChainUpdateUtils() {} + // TODO 都在一个区块内,应该优化到区块内的方块getter public static void noteBlockChainUpdate(Object level, Object chunkSource, Object direction, Object blockPos, int times) { - if (times >= Config.maxChainUpdate()) return; + if (times-- < 0) return; Object relativePos = FastNMS.INSTANCE.method$BlockPos$relative(blockPos, direction); Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, relativePos); if (BlockStateUtils.isClientSideNoteBlock(state)) { FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, relativePos); - noteBlockChainUpdate(level, chunkSource, direction, relativePos, times+1); + noteBlockChainUpdate(level, chunkSource, direction, relativePos, times); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java index d5754abde..f6e8bf219 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RegistryUtils.java @@ -19,7 +19,7 @@ public class RegistryUtils { public static int currentBiomeRegistrySize() { try { - Object idMap = CoreReflections.method$Registry$asHolderIdMap.invoke(CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.instance$Registries$BIOME)); + Object idMap = CoreReflections.method$Registry$asHolderIdMap.invoke(CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.BIOME)); return (int) CoreReflections.method$IdMap$size.invoke(idMap); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index 839f8055a..593435b06 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -1,20 +1,14 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.util.EntityUtils; -import net.momirealms.craftengine.bukkit.util.ItemUtils; -import net.momirealms.craftengine.bukkit.util.ParticleUtils; -import net.momirealms.craftengine.bukkit.util.SoundUtils; +import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.BlockInWorld; -import net.momirealms.craftengine.core.world.Position; -import net.momirealms.craftengine.core.world.World; -import net.momirealms.craftengine.core.world.WorldHeight; +import net.momirealms.craftengine.core.world.*; import net.momirealms.craftengine.core.world.particle.ParticleData; import org.bukkit.Location; import org.bukkit.Particle; @@ -124,4 +118,9 @@ public class BukkitWorld implements World { Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z); FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState.handle(), flags); } + + @Override + public void levelEvent(int id, BlockPos pos, int data) { + FastNMS.INSTANCE.method$Level$levelEvent(serverWorld(), id, LocationUtils.toBlockPos(pos), data); + } } diff --git a/common-files/src/main/resources/commands.yml b/common-files/src/main/resources/commands.yml index d600a8e7c..17aa9c83e 100644 --- a/common-files/src/main/resources/commands.yml +++ b/common-files/src/main/resources/commands.yml @@ -182,6 +182,20 @@ debug_clear_cooldown: - /craftengine debug clear-cooldown - /ce debug clear-cooldown +debug_entity_id_to_uuid: + enable: true + permission: ce.command.debug.entity_id_to_uuid + usage: + - /craftengine debug entity-id-to-uuid + - /ce debug entity-id-to-uuid + +debug_migrate_templates: + enable: true + permission: ce.command.debug.migrate_templates + usage: + - /craftengine debug migrate-templates + - /ce debug migrate-templates + debug_test: enable: true permission: ce.command.debug.test diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index b01304628..da3f8d719 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -49,12 +49,14 @@ resource-pack: bypass-textures: # - minecraft:block/farmland - "@legacy_unicode" - - "@vanilla_font_textures" - - "@vanilla_item_textures" - - "@vanilla_block_textures" - bypass-models: [] + - "@vanilla_textures" + bypass-models: + - "@vanilla_models" bypass-sounds: [] bypass-equipments: [] + # Validate if there are any errors in the resource pack, such as missing textures or models + validate: + enable: true supported-version: min: "1.20" max: LATEST @@ -336,7 +338,7 @@ gui: performance: # Maximum chain update depth when fixing client visuals - max-block-chain-update-limit: 64 + max-note-block-chain-update-limit: 48 # Prevent lag or oversized packet when processing emoji-heavy content max-emojis-per-parse: 16 diff --git a/common-files/src/main/resources/internal/models/item/_all.json b/common-files/src/main/resources/internal/models/item/_all.json new file mode 100644 index 000000000..ec6faaf6d --- /dev/null +++ b/common-files/src/main/resources/internal/models/item/_all.json @@ -0,0 +1 @@ +{"acacia_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/acacia_boat"}},"acacia_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/acacia_chest_boat"}},"acacia_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/acacia_door"}},"acacia_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/acacia_hanging_sign"}},"acacia_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/acacia_sapling"}},"acacia_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/acacia_sign"}},"activator_rail":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/activator_rail"}},"air":{"textures":{"particle":"minecraft:missingno"}},"allium":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/allium"}},"amethyst_bud":{"parent":"minecraft:item/generated","display":{"firstperson_righthand":{"rotation":[0,-90,25],"translation":[0,5,0],"scale":[0.68,0.68,0.68]},"thirdperson_righthand":{"translation":[0,4,1],"scale":[0.55,0.55,0.55]},"head":{"translation":[0,14,-5]},"gui":{"translation":[0,2,0]}}},"amethyst_cluster":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/amethyst_cluster"},"display":{"head":{"translation":[0,14,-5]}}},"amethyst_shard":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/amethyst_shard"}},"angler_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/angler_pottery_sherd"}},"apple":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/apple"}},"archer_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/archer_pottery_sherd"}},"armadillo_scute":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/armadillo_scute"}},"armor_stand":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/armor_stand"}},"arms_up_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/arms_up_pottery_sherd"}},"arrow":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/arrow"}},"axolotl_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/axolotl_bucket"}},"azure_bluet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/azure_bluet"}},"baked_potato":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/baked_potato"}},"bamboo":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/bamboo"}},"bamboo_chest_raft":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bamboo_chest_raft"}},"bamboo_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bamboo_door"}},"bamboo_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bamboo_hanging_sign"}},"bamboo_raft":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bamboo_raft"}},"bamboo_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bamboo_sign"}},"barrier":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/barrier"}},"beef":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/beef"}},"beetroot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/beetroot"}},"beetroot_seeds":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/beetroot_seeds"}},"beetroot_soup":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/beetroot_soup"}},"bell":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bell"}},"big_dripleaf":{"parent":"minecraft:block/big_dripleaf","display":{"gui":{"rotation":[30,225,0],"translation":[0,-2,0],"scale":[0.625,0.625,0.625]},"fixed":{"rotation":[0,0,0],"translation":[0,0,-1],"scale":[0.5,0.5,0.5]},"thirdperson_righthand":{"rotation":[0,0,0],"translation":[0,1,0],"scale":[0.55,0.55,0.55]},"firstperson_righthand":{"rotation":[0,0,0],"translation":[1.13,0,1.13],"scale":[0.68,0.68,0.68]}}},"birch_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/birch_boat"}},"birch_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/birch_chest_boat"}},"birch_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/birch_door"}},"birch_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/birch_hanging_sign"}},"birch_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/birch_sapling"}},"birch_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/birch_sign"}},"black_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/black_wool"}},"black_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/black_bundle"}},"black_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/black_bundle_open_back"}},"black_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/black_bundle_open_front"}},"black_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/black_candle"}},"black_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/black_dye"}},"black_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/black_shulker_box"}},"black_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/black_stained_glass"}},"blade_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blade_pottery_sherd"}},"blaze_powder":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blaze_powder"}},"blaze_rod":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/blaze_rod"}},"blue_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/blue_wool"}},"blue_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blue_bundle"}},"blue_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/blue_bundle_open_back"}},"blue_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/blue_bundle_open_front"}},"blue_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blue_candle"}},"blue_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blue_dye"}},"blue_orchid":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/blue_orchid"}},"blue_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/blue_shulker_box"}},"blue_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/blue_stained_glass"}},"bolt_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bolt_armor_trim_smithing_template"}},"bone":{"parent":"item/handheld","textures":{"layer0":"item/bone"},"display":{"head":{"rotation":[0,0,-45],"translation":[0,-4.5,-6.5],"scale":[1,1,1]}}},"bone_meal":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bone_meal"}},"book":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/book"}},"bordure_indented_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bordure_indented_banner_pattern"}},"bow":{"parent":"item/generated","textures":{"layer0":"item/bow"},"display":{"thirdperson_righthand":{"rotation":[-80,260,-40],"translation":[-1,-2,2.5],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[-80,-280,40],"translation":[-1,-2,2.5],"scale":[0.9,0.9,0.9]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]}}},"bow_pulling_0":{"parent":"minecraft:item/bow","textures":{"layer0":"minecraft:item/bow_pulling_0"}},"bow_pulling_1":{"parent":"minecraft:item/bow","textures":{"layer0":"minecraft:item/bow_pulling_1"}},"bow_pulling_2":{"parent":"minecraft:item/bow","textures":{"layer0":"minecraft:item/bow_pulling_2"}},"bowl":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bowl"}},"brain_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/brain_coral"}},"brain_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/brain_coral_fan"}},"bread":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bread"}},"breeze_rod":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/breeze_rod"}},"brewer_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brewer_pottery_sherd"}},"brewing_stand":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brewing_stand"}},"brick":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brick"}},"brown_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/brown_wool"}},"brown_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brown_bundle"}},"brown_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/brown_bundle_open_back"}},"brown_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/brown_bundle_open_front"}},"brown_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brown_candle"}},"brown_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brown_dye"}},"brown_mushroom":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/brown_mushroom"}},"brown_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/brown_shulker_box"}},"brown_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/brown_stained_glass"}},"brush":{"parent":"item/generated","textures":{"layer0":"item/brush"},"display":{"firstperson_lefthand":{"rotation":[55,-85,0],"translation":[8.0,0.5,-5.5],"scale":[1.0,1.0,1.0]},"thirdperson_righthand":{"rotation":[0,0,45],"translation":[0,4,0],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[0,0,-45],"translation":[0,4,0],"scale":[0.9,0.9,0.9]}}},"brush_brushing_0":{"parent":"item/generated","textures":{"layer0":"item/brush"},"display":{"firstperson_lefthand":{"rotation":[55,-85,0],"translation":[8.0,0.5,-5.5],"scale":[1.0,1.0,1.0]},"thirdperson_righthand":{"rotation":[0,0,0],"translation":[4,2,0],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[0,0,0],"translation":[-4,2,0],"scale":[0.9,0.9,0.9]}}},"brush_brushing_1":{"parent":"item/generated","textures":{"layer0":"item/brush"},"display":{"firstperson_lefthand":{"rotation":[55,-85,0],"translation":[8.0,0.5,-5.5],"scale":[1.0,1.0,1.0]},"thirdperson_righthand":{"rotation":[0,0,45],"translation":[0,4,0],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[0,0,-45],"translation":[0,4,0],"scale":[0.9,0.9,0.9]}}},"brush_brushing_2":{"parent":"item/generated","textures":{"layer0":"item/brush"},"display":{"firstperson_lefthand":{"rotation":[55,-85,0],"translation":[8.0,0.5,-5.5],"scale":[1.0,1.0,1.0]},"thirdperson_righthand":{"rotation":[0,0,90],"translation":[-4,2,0],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[0,0,-90],"translation":[4,2,0],"scale":[0.9,0.9,0.9]}}},"bubble_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/bubble_coral"}},"bubble_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/bubble_coral_fan"}},"bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bucket"}},"bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bundle"}},"bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/bundle_open_back"}},"bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/bundle_open_front"}},"burn_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/burn_pottery_sherd"}},"cake":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cake"}},"campfire":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/campfire"}},"candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/candle"}},"carrot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/carrot"}},"carrot_on_a_stick":{"parent":"minecraft:item/handheld_rod","textures":{"layer0":"minecraft:item/carrot_on_a_stick"}},"cauldron":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cauldron"}},"chain":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chain"}},"chainmail_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots"}},"chainmail_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_amethyst"}},"chainmail_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_copper"}},"chainmail_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_diamond"}},"chainmail_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_emerald"}},"chainmail_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_gold"}},"chainmail_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_iron"}},"chainmail_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_lapis"}},"chainmail_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_netherite"}},"chainmail_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_quartz"}},"chainmail_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_redstone"}},"chainmail_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_resin"}},"chainmail_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate"}},"chainmail_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_amethyst"}},"chainmail_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_copper"}},"chainmail_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_diamond"}},"chainmail_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_emerald"}},"chainmail_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_gold"}},"chainmail_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_iron"}},"chainmail_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_lapis"}},"chainmail_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_netherite"}},"chainmail_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_quartz"}},"chainmail_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_redstone"}},"chainmail_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_resin"}},"chainmail_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet"}},"chainmail_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"chainmail_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"chainmail_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond"}},"chainmail_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"chainmail_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_gold"}},"chainmail_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_iron"}},"chainmail_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"chainmail_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite"}},"chainmail_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"chainmail_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"chainmail_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"chainmail_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings"}},"chainmail_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_amethyst"}},"chainmail_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_copper"}},"chainmail_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_diamond"}},"chainmail_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_emerald"}},"chainmail_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_gold"}},"chainmail_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_iron"}},"chainmail_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_lapis"}},"chainmail_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_netherite"}},"chainmail_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_quartz"}},"chainmail_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_redstone"}},"chainmail_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_resin"}},"charcoal":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/charcoal"}},"cherry_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cherry_boat"}},"cherry_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cherry_chest_boat"}},"cherry_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cherry_door"}},"cherry_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cherry_hanging_sign"}},"cherry_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/cherry_sapling"}},"cherry_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cherry_sign"}},"chest":{"parent":"minecraft:item/template_chest","textures":{"particle":"minecraft:block/oak_planks"}},"chest_minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chest_minecart"}},"chicken":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chicken"}},"chorus_fruit":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chorus_fruit"}},"clay_ball":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clay_ball"}},"clock_00":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_00"}},"clock_01":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_01"}},"clock_02":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_02"}},"clock_03":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_03"}},"clock_04":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_04"}},"clock_05":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_05"}},"clock_06":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_06"}},"clock_07":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_07"}},"clock_08":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_08"}},"clock_09":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_09"}},"clock_10":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_10"}},"clock_11":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_11"}},"clock_12":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_12"}},"clock_13":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_13"}},"clock_14":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_14"}},"clock_15":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_15"}},"clock_16":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_16"}},"clock_17":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_17"}},"clock_18":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_18"}},"clock_19":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_19"}},"clock_20":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_20"}},"clock_21":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_21"}},"clock_22":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_22"}},"clock_23":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_23"}},"clock_24":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_24"}},"clock_25":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_25"}},"clock_26":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_26"}},"clock_27":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_27"}},"clock_28":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_28"}},"clock_29":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_29"}},"clock_30":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_30"}},"clock_31":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_31"}},"clock_32":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_32"}},"clock_33":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_33"}},"clock_34":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_34"}},"clock_35":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_35"}},"clock_36":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_36"}},"clock_37":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_37"}},"clock_38":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_38"}},"clock_39":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_39"}},"clock_40":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_40"}},"clock_41":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_41"}},"clock_42":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_42"}},"clock_43":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_43"}},"clock_44":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_44"}},"clock_45":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_45"}},"clock_46":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_46"}},"clock_47":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_47"}},"clock_48":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_48"}},"clock_49":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_49"}},"clock_50":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_50"}},"clock_51":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_51"}},"clock_52":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_52"}},"clock_53":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_53"}},"clock_54":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_54"}},"clock_55":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_55"}},"clock_56":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_56"}},"clock_57":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_57"}},"clock_58":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_58"}},"clock_59":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_59"}},"clock_60":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_60"}},"clock_61":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_61"}},"clock_62":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_62"}},"clock_63":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_63"}},"closed_eyeblossom":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/closed_eyeblossom"}},"coal":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/coal"}},"coast_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/coast_armor_trim_smithing_template"}},"cobweb":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/cobweb"}},"cocoa_beans":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cocoa_beans"}},"cod":{"parent":"item/generated","textures":{"layer0":"item/cod"},"display":{"head":{"rotation":[0,90,-60],"translation":[-7,-4,-7],"scale":[0.8,0.8,0.8]}}},"cod_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cod_bucket"}},"command_block_minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/command_block_minecart"}},"comparator":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/comparator"}},"compass_00":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_00"}},"compass_01":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_01"}},"compass_02":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_02"}},"compass_03":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_03"}},"compass_04":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_04"}},"compass_05":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_05"}},"compass_06":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_06"}},"compass_07":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_07"}},"compass_08":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_08"}},"compass_09":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_09"}},"compass_10":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_10"}},"compass_11":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_11"}},"compass_12":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_12"}},"compass_13":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_13"}},"compass_14":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_14"}},"compass_15":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_15"}},"compass_16":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_16"}},"compass_17":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_17"}},"compass_18":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_18"}},"compass_19":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_19"}},"compass_20":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_20"}},"compass_21":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_21"}},"compass_22":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_22"}},"compass_23":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_23"}},"compass_24":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_24"}},"compass_25":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_25"}},"compass_26":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_26"}},"compass_27":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_27"}},"compass_28":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_28"}},"compass_29":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_29"}},"compass_30":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_30"}},"compass_31":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_31"}},"conduit":{"textures":{"particle":"block/conduit"},"display":{"gui":{"rotation":[30,45,0],"translation":[0,0,0],"scale":[1.0,1.0,1.0]},"ground":{"rotation":[0,0,0],"translation":[0,3,0],"scale":[0.5,0.5,0.5]},"head":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[1,1,1]},"fixed":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[1,1,1]},"thirdperson_righthand":{"rotation":[75,315,0],"translation":[0,2.5,0],"scale":[0.5,0.5,0.5]},"firstperson_righthand":{"rotation":[0,315,0],"translation":[0,0,0],"scale":[0.8,0.8,0.8]}}},"cooked_beef":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_beef"}},"cooked_chicken":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_chicken"}},"cooked_cod":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_cod"}},"cooked_mutton":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_mutton"}},"cooked_porkchop":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_porkchop"}},"cooked_rabbit":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_rabbit"}},"cooked_salmon":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_salmon"}},"cookie":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cookie"}},"copper_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/copper_door"}},"copper_ingot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/copper_ingot"}},"cornflower":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/cornflower"}},"creeper_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/creeper_banner_pattern"}},"crimson_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/crimson_door"}},"crimson_fungus":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/crimson_fungus"}},"crimson_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/crimson_hanging_sign"}},"crimson_roots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/crimson_roots"}},"crimson_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/crimson_sign"}},"crossbow":{"parent":"item/generated","textures":{"layer0":"item/crossbow_standby"},"display":{"thirdperson_righthand":{"rotation":[-90,0,-60],"translation":[2,0.1,-3],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[-90,0,30],"translation":[2,0.1,-3],"scale":[0.9,0.9,0.9]},"firstperson_righthand":{"rotation":[-90,0,-55],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]},"firstperson_lefthand":{"rotation":[-90,0,35],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]}}},"crossbow_arrow":{"parent":"minecraft:item/crossbow","textures":{"layer0":"minecraft:item/crossbow_arrow"}},"crossbow_firework":{"parent":"minecraft:item/crossbow","textures":{"layer0":"minecraft:item/crossbow_firework"}},"crossbow_pulling_0":{"parent":"minecraft:item/crossbow","textures":{"layer0":"minecraft:item/crossbow_pulling_0"}},"crossbow_pulling_1":{"parent":"minecraft:item/crossbow","textures":{"layer0":"minecraft:item/crossbow_pulling_1"}},"crossbow_pulling_2":{"parent":"minecraft:item/crossbow","textures":{"layer0":"minecraft:item/crossbow_pulling_2"}},"cyan_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/cyan_wool"}},"cyan_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cyan_bundle"}},"cyan_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/cyan_bundle_open_back"}},"cyan_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/cyan_bundle_open_front"}},"cyan_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cyan_candle"}},"cyan_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cyan_dye"}},"cyan_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/cyan_shulker_box"}},"cyan_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/cyan_stained_glass"}},"dandelion":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dandelion"}},"danger_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/danger_pottery_sherd"}},"dark_oak_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dark_oak_boat"}},"dark_oak_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dark_oak_chest_boat"}},"dark_oak_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dark_oak_door"}},"dark_oak_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dark_oak_hanging_sign"}},"dark_oak_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dark_oak_sapling"}},"dark_oak_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dark_oak_sign"}},"dead_brain_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_brain_coral"}},"dead_brain_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_brain_coral_fan"}},"dead_bubble_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_bubble_coral"}},"dead_bubble_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_bubble_coral_fan"}},"dead_bush":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_bush"}},"dead_fire_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_fire_coral"}},"dead_fire_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_fire_coral_fan"}},"dead_horn_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_horn_coral"}},"dead_horn_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_horn_coral_fan"}},"dead_tube_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_tube_coral"}},"dead_tube_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_tube_coral_fan"}},"debug_stick":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stick"}},"decorated_pot":{"gui_light":"front","textures":{"particle":"entity/decorated_pot/decorated_pot_side"},"display":{"thirdperson_righthand":{"rotation":[0,90,0],"translation":[0,2,0.5],"scale":[0.375,0.375,0.375]},"firstperson_righthand":{"rotation":[0,90,0],"translation":[0,0,0],"scale":[0.375,0.375,0.375]},"gui":{"rotation":[30,45,0],"translation":[0,0,0],"scale":[0.60,0.60,0.60]},"ground":{"rotation":[0,0,0],"translation":[0,1,0],"scale":[0.25,0.25,0.25]},"head":{"rotation":[0,180,0],"translation":[0,16,0],"scale":[1.5,1.5,1.5]},"fixed":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[0.5,0.5,0.5]}}},"detector_rail":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/detector_rail"}},"diamond":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond"}},"diamond_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/diamond_axe"}},"diamond_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots"}},"diamond_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_amethyst"}},"diamond_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_copper"}},"diamond_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_diamond_darker"}},"diamond_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_emerald"}},"diamond_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_gold"}},"diamond_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_iron"}},"diamond_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_lapis"}},"diamond_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_netherite"}},"diamond_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_quartz"}},"diamond_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_redstone"}},"diamond_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_resin"}},"diamond_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate"}},"diamond_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_amethyst"}},"diamond_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_copper"}},"diamond_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_diamond_darker"}},"diamond_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_emerald"}},"diamond_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_gold"}},"diamond_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_iron"}},"diamond_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_lapis"}},"diamond_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_netherite"}},"diamond_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_quartz"}},"diamond_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_redstone"}},"diamond_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_resin"}},"diamond_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet"}},"diamond_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"diamond_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"diamond_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond_darker"}},"diamond_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"diamond_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_gold"}},"diamond_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_iron"}},"diamond_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"diamond_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite"}},"diamond_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"diamond_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"diamond_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"diamond_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/diamond_hoe"}},"diamond_horse_armor":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_horse_armor"}},"diamond_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings"}},"diamond_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_amethyst"}},"diamond_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_copper"}},"diamond_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_diamond_darker"}},"diamond_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_emerald"}},"diamond_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_gold"}},"diamond_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_iron"}},"diamond_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_lapis"}},"diamond_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_netherite"}},"diamond_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_quartz"}},"diamond_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_redstone"}},"diamond_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_resin"}},"diamond_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/diamond_pickaxe"}},"diamond_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/diamond_shovel"}},"diamond_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/diamond_sword"}},"disc_fragment_5":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/disc_fragment_5"}},"dragon_breath":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dragon_breath"}},"dragon_head":{"parent":"item/template_skull","display":{"gui":{"translation":[-2,2,0],"rotation":[30,45,0],"scale":[0.6,0.6,0.6]},"thirdperson_righthand":{"rotation":[0,180,0],"translation":[0,-1,2],"scale":[0.5,0.5,0.5]}}},"dried_kelp":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dried_kelp"}},"dune_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dune_armor_trim_smithing_template"}},"echo_shard":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/echo_shard"}},"egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/egg"}},"elytra":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/elytra"}},"elytra_broken":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/elytra_broken"}},"emerald":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/emerald"}},"enchanted_book":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/enchanted_book"}},"enchanted_golden_apple":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_apple"}},"end_crystal":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/end_crystal"}},"ender_chest":{"parent":"minecraft:item/template_chest","textures":{"particle":"minecraft:block/obsidian"}},"ender_eye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ender_eye"}},"ender_pearl":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ender_pearl"}},"experience_bottle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/experience_bottle"}},"explorer_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/explorer_pottery_sherd"}},"exposed_copper_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/exposed_copper_door"}},"eye_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/eye_armor_trim_smithing_template"}},"feather":{"parent":"item/generated","textures":{"layer0":"item/feather"},"display":{"head":{"rotation":[0,0,45],"translation":[-1,13,7],"scale":[1,1,1]}}},"fermented_spider_eye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/fermented_spider_eye"}},"fern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/fern"}},"field_masoned_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/field_masoned_banner_pattern"}},"filled_map":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/filled_map","layer1":"minecraft:item/filled_map_markings"}},"fire_charge":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/fire_charge"}},"fire_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/fire_coral"}},"fire_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/fire_coral_fan"}},"firework_rocket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/firework_rocket"}},"firework_star":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/firework_star","layer1":"minecraft:item/firework_star_overlay"}},"fishing_rod":{"parent":"minecraft:item/handheld_rod","textures":{"layer0":"minecraft:item/fishing_rod"}},"fishing_rod_cast":{"parent":"minecraft:item/handheld_rod","textures":{"layer0":"minecraft:item/fishing_rod_cast"}},"flint":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flint"}},"flint_and_steel":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flint_and_steel"}},"flow_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flow_armor_trim_smithing_template"}},"flow_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flow_banner_pattern"}},"flow_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flow_pottery_sherd"}},"flower_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flower_banner_pattern"}},"flower_pot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flower_pot"}},"friend_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/friend_pottery_sherd"}},"frogspawn":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/frogspawn"}},"furnace_minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/furnace_minecart"}},"generated":{"parent":"builtin/generated","gui_light":"front","display":{"ground":{"rotation":[0,0,0],"translation":[0,2,0],"scale":[0.5,0.5,0.5]},"head":{"rotation":[0,180,0],"translation":[0,13,7],"scale":[1,1,1]},"thirdperson_righthand":{"rotation":[0,0,0],"translation":[0,3,1],"scale":[0.55,0.55,0.55]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]},"fixed":{"rotation":[0,180,0],"scale":[1,1,1]}}},"ghast_tear":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ghast_tear"}},"glass_bottle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glass_bottle"}},"glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/glass"}},"glistering_melon_slice":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glistering_melon_slice"}},"globe_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/globe_banner_pattern"}},"glow_berries":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glow_berries"}},"glow_ink_sac":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glow_ink_sac"}},"glow_item_frame":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glow_item_frame"}},"glow_lichen":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/glow_lichen"}},"glowstone_dust":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glowstone_dust"}},"goat_horn":{"parent":"item/generated","textures":{"layer0":"item/goat_horn"},"display":{"thirdperson_righthand":{"rotation":[0,180,0],"translation":[0,3,1],"scale":[0.55,0.55,0.55]},"thirdperson_lefthand":{"rotation":[0,0,0],"translation":[0,3,1],"scale":[0.55,0.55,0.55]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]}}},"gold_ingot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gold_ingot"}},"gold_nugget":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gold_nugget"}},"golden_apple":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_apple"}},"golden_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/golden_axe"}},"golden_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots"}},"golden_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_amethyst"}},"golden_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_copper"}},"golden_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_diamond"}},"golden_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_emerald"}},"golden_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_gold_darker"}},"golden_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_iron"}},"golden_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_lapis"}},"golden_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_netherite"}},"golden_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_quartz"}},"golden_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_redstone"}},"golden_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_resin"}},"golden_carrot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_carrot"}},"golden_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate"}},"golden_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_amethyst"}},"golden_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_copper"}},"golden_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_diamond"}},"golden_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_emerald"}},"golden_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_gold_darker"}},"golden_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_iron"}},"golden_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_lapis"}},"golden_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_netherite"}},"golden_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_quartz"}},"golden_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_redstone"}},"golden_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_resin"}},"golden_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet"}},"golden_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"golden_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"golden_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond"}},"golden_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"golden_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_gold_darker"}},"golden_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_iron"}},"golden_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"golden_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite"}},"golden_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"golden_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"golden_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"golden_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/golden_hoe"}},"golden_horse_armor":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_horse_armor"}},"golden_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings"}},"golden_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_amethyst"}},"golden_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_copper"}},"golden_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_diamond"}},"golden_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_emerald"}},"golden_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_gold_darker"}},"golden_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_iron"}},"golden_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_lapis"}},"golden_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_netherite"}},"golden_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_quartz"}},"golden_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_redstone"}},"golden_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_resin"}},"golden_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/golden_pickaxe"}},"golden_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/golden_shovel"}},"golden_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/golden_sword"}},"gray_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/gray_wool"}},"gray_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gray_bundle"}},"gray_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/gray_bundle_open_back"}},"gray_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/gray_bundle_open_front"}},"gray_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gray_candle"}},"gray_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gray_dye"}},"gray_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/gray_shulker_box"}},"gray_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/gray_stained_glass"}},"green_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/green_wool"}},"green_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/green_bundle"}},"green_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/green_bundle_open_back"}},"green_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/green_bundle_open_front"}},"green_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/green_candle"}},"green_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/green_dye"}},"green_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/green_shulker_box"}},"green_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/green_stained_glass"}},"gunpowder":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gunpowder"}},"guster_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/guster_banner_pattern"}},"guster_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/guster_pottery_sherd"}},"handheld":{"parent":"item/generated","display":{"thirdperson_righthand":{"rotation":[0,-90,55],"translation":[0,4.0,0.5],"scale":[0.85,0.85,0.85]},"thirdperson_lefthand":{"rotation":[0,90,-55],"translation":[0,4.0,0.5],"scale":[0.85,0.85,0.85]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]}}},"handheld_mace":{"parent":"item/handheld","display":{"thirdperson_righthand":{"rotation":[0,-90,55],"translation":[0,4.0,1],"scale":[1,1,1]},"thirdperson_lefthand":{"rotation":[0,90,-55],"translation":[0,4.0,1],"scale":[1,1,1]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[0,3,0.8],"scale":[0.9,0.9,0.9]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[0,3,0.8],"scale":[0.9,0.9,0.9]}}},"handheld_rod":{"parent":"item/handheld","display":{"thirdperson_righthand":{"rotation":[0,90,55],"translation":[0,4.0,2.5],"scale":[0.85,0.85,0.85]},"thirdperson_lefthand":{"rotation":[0,-90,-55],"translation":[0,4.0,2.5],"scale":[0.85,0.85,0.85]},"firstperson_righthand":{"rotation":[0,90,25],"translation":[0,1.6,0.8],"scale":[0.68,0.68,0.68]},"firstperson_lefthand":{"rotation":[0,-90,-25],"translation":[0,1.6,0.8],"scale":[0.68,0.68,0.68]}}},"hanging_roots":{"parent":"item/generated","textures":{"layer0":"minecraft:block/hanging_roots"},"display":{"thirdperson_righthand":{"rotation":[0,0,0],"translation":[0,0,1],"scale":[0.55,0.55,0.55]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[1.13,0,1.13],"scale":[0.68,0.68,0.68]}}},"heart_of_the_sea":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/heart_of_the_sea"}},"heart_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/heart_pottery_sherd"}},"heartbreak_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/heartbreak_pottery_sherd"}},"honey_bottle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/honey_bottle"}},"honeycomb":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/honeycomb"}},"hopper":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/hopper"}},"hopper_minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/hopper_minecart"}},"horn_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/horn_coral"}},"horn_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/horn_coral_fan"}},"host_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/host_armor_trim_smithing_template"}},"howl_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/howl_pottery_sherd"}},"ink_sac":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ink_sac"}},"iron_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/iron_axe"}},"iron_bars":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/iron_bars"}},"iron_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots"}},"iron_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_amethyst"}},"iron_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_copper"}},"iron_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_diamond"}},"iron_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_emerald"}},"iron_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_gold"}},"iron_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_iron_darker"}},"iron_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_lapis"}},"iron_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_netherite"}},"iron_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_quartz"}},"iron_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_redstone"}},"iron_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_resin"}},"iron_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate"}},"iron_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_amethyst"}},"iron_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_copper"}},"iron_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_diamond"}},"iron_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_emerald"}},"iron_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_gold"}},"iron_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_iron_darker"}},"iron_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_lapis"}},"iron_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_netherite"}},"iron_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_quartz"}},"iron_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_redstone"}},"iron_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_resin"}},"iron_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_door"}},"iron_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet"}},"iron_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"iron_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"iron_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond"}},"iron_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"iron_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_gold"}},"iron_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_iron_darker"}},"iron_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"iron_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite"}},"iron_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"iron_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"iron_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"iron_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/iron_hoe"}},"iron_horse_armor":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_horse_armor"}},"iron_ingot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_ingot"}},"iron_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings"}},"iron_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_amethyst"}},"iron_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_copper"}},"iron_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_diamond"}},"iron_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_emerald"}},"iron_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_gold"}},"iron_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_iron_darker"}},"iron_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_lapis"}},"iron_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_netherite"}},"iron_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_quartz"}},"iron_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_redstone"}},"iron_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_resin"}},"iron_nugget":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_nugget"}},"iron_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/iron_pickaxe"}},"iron_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/iron_shovel"}},"iron_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/iron_sword"}},"item_frame":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/item_frame"}},"jungle_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/jungle_boat"}},"jungle_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/jungle_chest_boat"}},"jungle_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/jungle_door"}},"jungle_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/jungle_hanging_sign"}},"jungle_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/jungle_sapling"}},"jungle_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/jungle_sign"}},"kelp":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/kelp"}},"knowledge_book":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/knowledge_book"}},"ladder":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/ladder"}},"lantern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lantern"}},"lapis_lazuli":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lapis_lazuli"}},"large_amethyst_bud":{"parent":"item/amethyst_bud","textures":{"layer0":"minecraft:block/large_amethyst_bud"},"display":{"fixed":{"translation":[0,4,0]}}},"large_fern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/large_fern_top"}},"lava_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lava_bucket"}},"lead":{"parent":"item/generated","textures":{"layer0":"item/lead"},"display":{"head":{"rotation":[0,0,0],"translation":[2.75,-2.75,-6.5],"scale":[0.8,0.8,0.8]}}},"leather":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather"}},"leather_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay"}},"leather_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_amethyst"}},"leather_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_copper"}},"leather_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_diamond"}},"leather_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_emerald"}},"leather_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_gold"}},"leather_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_iron"}},"leather_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_lapis"}},"leather_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_netherite"}},"leather_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_quartz"}},"leather_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_redstone"}},"leather_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_resin"}},"leather_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay"}},"leather_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_amethyst"}},"leather_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_copper"}},"leather_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_diamond"}},"leather_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_emerald"}},"leather_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_gold"}},"leather_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_iron"}},"leather_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_lapis"}},"leather_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_netherite"}},"leather_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_quartz"}},"leather_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_redstone"}},"leather_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_resin"}},"leather_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay"}},"leather_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_amethyst"}},"leather_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_copper"}},"leather_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_diamond"}},"leather_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_emerald"}},"leather_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_gold"}},"leather_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_iron"}},"leather_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_lapis"}},"leather_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_netherite"}},"leather_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_quartz"}},"leather_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_redstone"}},"leather_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_resin"}},"leather_horse_armor":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_horse_armor"}},"leather_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay"}},"leather_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_amethyst"}},"leather_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_copper"}},"leather_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_diamond"}},"leather_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_emerald"}},"leather_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_gold"}},"leather_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_iron"}},"leather_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_lapis"}},"leather_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_netherite"}},"leather_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_quartz"}},"leather_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_redstone"}},"leather_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_resin"}},"lever":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/lever"}},"light":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light"}},"light_00":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_00"}},"light_01":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_01"}},"light_02":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_02"}},"light_03":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_03"}},"light_04":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_04"}},"light_05":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_05"}},"light_06":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_06"}},"light_07":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_07"}},"light_08":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_08"}},"light_09":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_09"}},"light_10":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_10"}},"light_11":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_11"}},"light_12":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_12"}},"light_13":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_13"}},"light_14":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_14"}},"light_15":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_15"}},"light_blue_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/light_blue_wool"}},"light_blue_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_blue_bundle"}},"light_blue_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/light_blue_bundle_open_back"}},"light_blue_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/light_blue_bundle_open_front"}},"light_blue_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_blue_candle"}},"light_blue_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_blue_dye"}},"light_blue_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/light_blue_shulker_box"}},"light_blue_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/light_blue_stained_glass"}},"light_gray_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/light_gray_wool"}},"light_gray_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_gray_bundle"}},"light_gray_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/light_gray_bundle_open_back"}},"light_gray_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/light_gray_bundle_open_front"}},"light_gray_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_gray_candle"}},"light_gray_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_gray_dye"}},"light_gray_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/light_gray_shulker_box"}},"light_gray_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/light_gray_stained_glass"}},"lilac":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/lilac_top"}},"lily_of_the_valley":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/lily_of_the_valley"}},"lily_pad":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/lily_pad"}},"lime_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/lime_wool"}},"lime_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lime_bundle"}},"lime_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/lime_bundle_open_back"}},"lime_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/lime_bundle_open_front"}},"lime_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lime_candle"}},"lime_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lime_dye"}},"lime_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/lime_shulker_box"}},"lime_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/lime_stained_glass"}},"lingering_potion":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/potion_overlay","layer1":"minecraft:item/lingering_potion"}},"mace":{"parent":"minecraft:item/handheld_mace","textures":{"layer0":"minecraft:item/mace"}},"magenta_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/magenta_wool"}},"magenta_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magenta_bundle"}},"magenta_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/magenta_bundle_open_back"}},"magenta_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/magenta_bundle_open_front"}},"magenta_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magenta_candle"}},"magenta_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magenta_dye"}},"magenta_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/magenta_shulker_box"}},"magenta_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/magenta_stained_glass"}},"magma_cream":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magma_cream"}},"mangrove_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_boat"}},"mangrove_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_chest_boat"}},"mangrove_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_door"}},"mangrove_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_hanging_sign"}},"mangrove_propagule":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_propagule"}},"mangrove_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_sign"}},"map":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/map"}},"medium_amethyst_bud":{"parent":"item/amethyst_bud","textures":{"layer0":"minecraft:block/medium_amethyst_bud"},"display":{"fixed":{"translation":[0,6,0]}}},"melon_seeds":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/melon_seeds"}},"melon_slice":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/melon_slice"}},"milk_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/milk_bucket"}},"minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/minecart"}},"miner_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/miner_pottery_sherd"}},"mojang_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mojang_banner_pattern"}},"mourner_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mourner_pottery_sherd"}},"mushroom_stew":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mushroom_stew"}},"music_disc_11":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_11"}},"music_disc_13":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_13"}},"music_disc_5":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_5"}},"music_disc_blocks":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_blocks"}},"music_disc_cat":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_cat"}},"music_disc_chirp":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_chirp"}},"music_disc_creator":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_creator"}},"music_disc_creator_music_box":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_creator_music_box"}},"music_disc_far":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_far"}},"music_disc_mall":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_mall"}},"music_disc_mellohi":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_mellohi"}},"music_disc_otherside":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_otherside"}},"music_disc_pigstep":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_pigstep"}},"music_disc_precipice":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_precipice"}},"music_disc_relic":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_relic"}},"music_disc_stal":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_stal"}},"music_disc_strad":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_strad"}},"music_disc_wait":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_wait"}},"music_disc_ward":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_ward"}},"mutton":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mutton"}},"name_tag":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/name_tag"}},"nautilus_shell":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/nautilus_shell"}},"nether_brick":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/nether_brick"}},"nether_sprouts":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/nether_sprouts"}},"nether_star":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/nether_star"}},"nether_wart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/nether_wart"}},"netherite_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/netherite_axe"}},"netherite_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots"}},"netherite_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_amethyst"}},"netherite_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_copper"}},"netherite_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_diamond"}},"netherite_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_emerald"}},"netherite_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_gold"}},"netherite_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_iron"}},"netherite_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_lapis"}},"netherite_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_netherite_darker"}},"netherite_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_quartz"}},"netherite_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_redstone"}},"netherite_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_resin"}},"netherite_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate"}},"netherite_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_amethyst"}},"netherite_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_copper"}},"netherite_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_diamond"}},"netherite_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_emerald"}},"netherite_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_gold"}},"netherite_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_iron"}},"netherite_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_lapis"}},"netherite_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_netherite_darker"}},"netherite_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_quartz"}},"netherite_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_redstone"}},"netherite_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_resin"}},"netherite_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet"}},"netherite_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"netherite_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"netherite_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond"}},"netherite_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"netherite_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_gold"}},"netherite_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_iron"}},"netherite_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"netherite_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite_darker"}},"netherite_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"netherite_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"netherite_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"netherite_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/netherite_hoe"}},"netherite_ingot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_ingot"}},"netherite_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings"}},"netherite_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_amethyst"}},"netherite_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_copper"}},"netherite_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_diamond"}},"netherite_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_emerald"}},"netherite_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_gold"}},"netherite_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_iron"}},"netherite_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_lapis"}},"netherite_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_netherite_darker"}},"netherite_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_quartz"}},"netherite_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_redstone"}},"netherite_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_resin"}},"netherite_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/netherite_pickaxe"}},"netherite_scrap":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_scrap"}},"netherite_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/netherite_shovel"}},"netherite_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/netherite_sword"}},"netherite_upgrade_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_upgrade_smithing_template"}},"oak_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oak_boat"}},"oak_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oak_chest_boat"}},"oak_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oak_door"}},"oak_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oak_hanging_sign"}},"oak_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/oak_sapling"}},"oak_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oak_sign"}},"ominous_bottle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ominous_bottle"}},"ominous_trial_key":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ominous_trial_key"}},"open_eyeblossom":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/open_eyeblossom","layer1":"minecraft:block/open_eyeblossom_emissive"}},"orange_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/orange_wool"}},"orange_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/orange_bundle"}},"orange_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/orange_bundle_open_back"}},"orange_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/orange_bundle_open_front"}},"orange_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/orange_candle"}},"orange_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/orange_dye"}},"orange_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/orange_shulker_box"}},"orange_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/orange_stained_glass"}},"orange_tulip":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/orange_tulip"}},"oxeye_daisy":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/oxeye_daisy"}},"oxidized_copper_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oxidized_copper_door"}},"painting":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/painting"}},"pale_hanging_moss":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/pale_hanging_moss"}},"pale_oak_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pale_oak_boat"}},"pale_oak_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pale_oak_chest_boat"}},"pale_oak_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pale_oak_door"}},"pale_oak_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pale_oak_hanging_sign"}},"pale_oak_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/pale_oak_sapling"}},"pale_oak_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pale_oak_sign"}},"paper":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/paper"}},"peony":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/peony_top"}},"phantom_membrane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/phantom_membrane"}},"piglin_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/piglin_banner_pattern"}},"pink_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/pink_wool"}},"pink_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pink_bundle"}},"pink_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/pink_bundle_open_back"}},"pink_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/pink_bundle_open_front"}},"pink_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pink_candle"}},"pink_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pink_dye"}},"pink_petals":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pink_petals"}},"pink_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/pink_shulker_box"}},"pink_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/pink_stained_glass"}},"pink_tulip":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/pink_tulip"}},"pitcher_plant":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pitcher_plant"}},"pitcher_pod":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pitcher_pod"}},"plenty_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/plenty_pottery_sherd"}},"pointed_dripstone":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pointed_dripstone"},"display":{"thirdperson_righthand":{"rotation":[0,100,0],"translation":[-1,-1,0],"scale":[0.9,0.9,0.9]},"firstperson_righthand":{"rotation":[0,100,0],"translation":[0,-2,0],"scale":[0.9,0.9,0.9]}}},"poisonous_potato":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/poisonous_potato"}},"popped_chorus_fruit":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/popped_chorus_fruit"}},"poppy":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/poppy"}},"porkchop":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/porkchop"}},"potato":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/potato"}},"potion":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/potion_overlay","layer1":"minecraft:item/potion"}},"powder_snow_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/powder_snow_bucket"}},"powered_rail":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/powered_rail"}},"prismarine_crystals":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/prismarine_crystals"}},"prismarine_shard":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/prismarine_shard"}},"prize_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/prize_pottery_sherd"}},"pufferfish":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pufferfish"}},"pufferfish_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pufferfish_bucket"}},"pumpkin_pie":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pumpkin_pie"}},"pumpkin_seeds":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pumpkin_seeds"}},"purple_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/purple_wool"}},"purple_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/purple_bundle"}},"purple_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/purple_bundle_open_back"}},"purple_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/purple_bundle_open_front"}},"purple_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/purple_candle"}},"purple_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/purple_dye"}},"purple_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/purple_shulker_box"}},"purple_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/purple_stained_glass"}},"quartz":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/quartz"}},"rabbit":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rabbit"}},"rabbit_foot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rabbit_foot"}},"rabbit_hide":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rabbit_hide"}},"rabbit_stew":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rabbit_stew"}},"rail":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/rail"}},"raiser_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/raiser_armor_trim_smithing_template"}},"raw_copper":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/raw_copper"}},"raw_gold":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/raw_gold"}},"raw_iron":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/raw_iron"}},"recovery_compass_00":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_00"}},"recovery_compass_01":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_01"}},"recovery_compass_02":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_02"}},"recovery_compass_03":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_03"}},"recovery_compass_04":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_04"}},"recovery_compass_05":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_05"}},"recovery_compass_06":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_06"}},"recovery_compass_07":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_07"}},"recovery_compass_08":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_08"}},"recovery_compass_09":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_09"}},"recovery_compass_10":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_10"}},"recovery_compass_11":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_11"}},"recovery_compass_12":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_12"}},"recovery_compass_13":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_13"}},"recovery_compass_14":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_14"}},"recovery_compass_15":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_15"}},"recovery_compass_16":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_16"}},"recovery_compass_17":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_17"}},"recovery_compass_18":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_18"}},"recovery_compass_19":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_19"}},"recovery_compass_20":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_20"}},"recovery_compass_21":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_21"}},"recovery_compass_22":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_22"}},"recovery_compass_23":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_23"}},"recovery_compass_24":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_24"}},"recovery_compass_25":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_25"}},"recovery_compass_26":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_26"}},"recovery_compass_27":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_27"}},"recovery_compass_28":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_28"}},"recovery_compass_29":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_29"}},"recovery_compass_30":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_30"}},"recovery_compass_31":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_31"}},"red_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/red_wool"}},"red_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/red_bundle"}},"red_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/red_bundle_open_back"}},"red_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/red_bundle_open_front"}},"red_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/red_candle"}},"red_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/red_dye"}},"red_mushroom":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/red_mushroom"}},"red_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/red_shulker_box"}},"red_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/red_stained_glass"}},"red_tulip":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/red_tulip"}},"redstone":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/redstone"}},"redstone_torch":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/redstone_torch"}},"repeater":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/repeater"}},"resin_brick":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/resin_brick"}},"resin_clump":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/resin_clump"}},"rib_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rib_armor_trim_smithing_template"}},"rose_bush":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/rose_bush_top"}},"rotten_flesh":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rotten_flesh"}},"saddle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/saddle"}},"salmon":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/salmon"}},"salmon_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/salmon_bucket"}},"scrape_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/scrape_pottery_sherd"}},"sculk_vein":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/sculk_vein"}},"sea_pickle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sea_pickle"}},"seagrass":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/seagrass"}},"sentry_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sentry_armor_trim_smithing_template"}},"shaper_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/shaper_armor_trim_smithing_template"}},"sheaf_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sheaf_pottery_sherd"}},"shears":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/shears"}},"shelter_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/shelter_pottery_sherd"}},"shield":{"gui_light":"front","textures":{"particle":"block/dark_oak_planks"},"display":{"thirdperson_righthand":{"rotation":[0,90,0],"translation":[10,6,-4],"scale":[1,1,1]},"thirdperson_lefthand":{"rotation":[0,90,0],"translation":[10,6,12],"scale":[1,1,1]},"firstperson_righthand":{"rotation":[0,180,5],"translation":[-10,2,-10],"scale":[1.25,1.25,1.25]},"firstperson_lefthand":{"rotation":[0,180,5],"translation":[10,0,-10],"scale":[1.25,1.25,1.25]},"gui":{"rotation":[15,-25,-5],"translation":[2,3,0],"scale":[0.65,0.65,0.65]},"fixed":{"rotation":[0,180,0],"translation":[-4.5,4.5,-5],"scale":[0.55,0.55,0.55]},"ground":{"rotation":[0,0,0],"translation":[2,4,2],"scale":[0.25,0.25,0.25]}}},"shield_blocking":{"gui_light":"front","textures":{"particle":"block/dark_oak_planks"},"display":{"thirdperson_righthand":{"rotation":[45,155,0],"translation":[-3.49,11,-2],"scale":[1,1,1]},"thirdperson_lefthand":{"rotation":[45,155,0],"translation":[11.51,7,2.5],"scale":[1,1,1]},"firstperson_righthand":{"rotation":[0,180,-5],"translation":[-15,5,-11],"scale":[1.25,1.25,1.25]},"firstperson_lefthand":{"rotation":[0,180,-5],"translation":[5,5,-11],"scale":[1.25,1.25,1.25]},"gui":{"rotation":[15,-25,-5],"translation":[2,3,0],"scale":[0.65,0.65,0.65]}}},"short_grass":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/short_grass"}},"shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/shulker_box"}},"shulker_shell":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/shulker_shell"}},"silence_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/silence_armor_trim_smithing_template"}},"skull_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/skull_banner_pattern"}},"skull_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/skull_pottery_sherd"}},"slime_ball":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/slime_ball"}},"small_amethyst_bud":{"parent":"item/amethyst_bud","textures":{"layer0":"minecraft:block/small_amethyst_bud"},"display":{"firstperson_righthand":{"rotation":[0,-90,25],"translation":[0,6,0],"scale":[0.68,0.68,0.68]},"fixed":{"translation":[0,7,0]}}},"small_dripleaf":{"parent":"minecraft:block/small_dripleaf_top","display":{"thirdperson_righthand":{"rotation":[0,0,0],"translation":[0,4,1],"scale":[0.55,0.55,0.55]},"firstperson_righthand":{"rotation":[0,45,0],"translation":[0,3.2,0],"scale":[0.40,0.40,0.40]}}},"sniffer_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sniffer_egg"}},"snort_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/snort_pottery_sherd"}},"snout_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/snout_armor_trim_smithing_template"}},"snowball":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/snowball"}},"soul_campfire":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/soul_campfire"}},"soul_lantern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/soul_lantern"}},"soul_torch":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/soul_torch"}},"spectral_arrow":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spectral_arrow"}},"spider_eye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spider_eye"}},"spire_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spire_armor_trim_smithing_template"}},"splash_potion":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/potion_overlay","layer1":"minecraft:item/splash_potion"}},"spruce_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spruce_boat"}},"spruce_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spruce_chest_boat"}},"spruce_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spruce_door"}},"spruce_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spruce_hanging_sign"}},"spruce_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/spruce_sapling"}},"spruce_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spruce_sign"}},"spyglass":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spyglass"}},"spyglass_in_hand":{"textures":{"spyglass":"item/spyglass_model","particle":"#spyglass"},"elements":[{"from":[7,8.5,7],"to":[9,13.5,9],"faces":{"north":{"uv":[0,2,2,7],"texture":"#spyglass"},"east":{"uv":[0,2,2,7],"texture":"#spyglass"},"south":{"uv":[0,2,2,7],"texture":"#spyglass"},"west":{"uv":[0,2,2,7],"texture":"#spyglass"},"up":{"uv":[0,0,2,2],"texture":"#spyglass"}}},{"from":[6.9,2.4,6.9],"to":[9.1,8.6,9.1],"faces":{"north":{"uv":[0,7,2,13],"texture":"#spyglass"},"east":{"uv":[0,7,2,13],"texture":"#spyglass"},"south":{"uv":[0,7,2,13],"texture":"#spyglass"},"west":{"uv":[0,7,2,13],"texture":"#spyglass"},"up":{"uv":[0,5,2,7],"texture":"#spyglass"},"down":{"uv":[0,13,2,15],"texture":"#spyglass"}}}],"gui_light":"front","display":{"thirdperson_righthand":{"translation":[0,-2,0]},"ground":{"rotation":[90,0,0]},"gui":{"rotation":[-67.5,0,45],"scale":[1.5,1.5,1.5]},"head":{"rotation":[90,0,0],"translation":[0,0,-16],"scale":[1.6,1.6,1.6]},"fixed":{"translation":[0,0,-1.5],"scale":[1.5,1.5,1.5]}}},"stick":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stick"}},"stone_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stone_axe"}},"stone_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stone_hoe"}},"stone_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stone_pickaxe"}},"stone_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stone_shovel"}},"stone_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stone_sword"}},"string":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/string"}},"structure_void":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/structure_void"}},"sugar":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sugar"}},"sugar_cane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sugar_cane"}},"sunflower":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/sunflower_front"}},"suspicious_stew":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/suspicious_stew"}},"sweet_berries":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sweet_berries"}},"tadpole_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tadpole_bucket"}},"tall_grass":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/tall_grass_top"}},"template_banner":{"gui_light":"front","textures":{"particle":"block/oak_planks"},"display":{"thirdperson_righthand":{"rotation":[0,90,0],"translation":[0,2,0.5],"scale":[0.375,0.375,0.375]},"firstperson_righthand":{"rotation":[0,90,0],"translation":[0,0,0],"scale":[0.375,0.375,0.375]},"gui":{"rotation":[30,20,0],"translation":[0,-3.25,0],"scale":[0.5325,0.5325,0.5325]},"ground":{"rotation":[0,0,0],"translation":[0,1,0],"scale":[0.25,0.25,0.25]},"head":{"rotation":[0,180,0],"translation":[0,16,7],"scale":[1.5,1.5,1.5]},"fixed":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[0.5,0.5,0.5]}}},"template_bed":{"display":{"thirdperson_righthand":{"rotation":[30,160,0],"translation":[0,3,-2],"scale":[0.23,0.23,0.23]},"firstperson_righthand":{"rotation":[30,160,0],"translation":[0,3,0],"scale":[0.375,0.375,0.375]},"gui":{"rotation":[30,160,0],"translation":[2,3,0],"scale":[0.5325,0.5325,0.5325]},"ground":{"rotation":[0,0,0],"translation":[0,1,2],"scale":[0.25,0.25,0.25]},"head":{"rotation":[0,180,0],"translation":[0,10,-8],"scale":[1,1,1]},"fixed":{"rotation":[270,0,0],"translation":[0,4,-2],"scale":[0.5,0.5,0.5]}}},"template_bundle_open_back":{"parent":"minecraft:item/generated","display":{"gui":{"translation":[0,0,-16]}}},"template_bundle_open_front":{"parent":"minecraft:item/generated","display":{"gui":{"translation":[0,0,16]}}},"template_chest":{"display":{"gui":{"rotation":[30,45,0],"translation":[0,0,0],"scale":[0.625,0.625,0.625]},"ground":{"rotation":[0,0,0],"translation":[0,3,0],"scale":[0.25,0.25,0.25]},"head":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[1,1,1]},"fixed":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[0.5,0.5,0.5]},"thirdperson_righthand":{"rotation":[75,315,0],"translation":[0,2.5,0],"scale":[0.375,0.375,0.375]},"firstperson_righthand":{"rotation":[0,315,0],"translation":[0,0,0],"scale":[0.4,0.4,0.4]}}},"template_music_disc":{"parent":"item/generated","gui_light":"front","display":{"fixed":{"rotation":[0,180,0],"translation":[-0.5,0,0]}}},"template_shulker_box":{"display":{"gui":{"rotation":[30,45,0],"translation":[0,0,0],"scale":[0.625,0.625,0.625]},"ground":{"rotation":[0,0,0],"translation":[0,3,0],"scale":[0.25,0.25,0.25]},"head":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[1,1,1]},"fixed":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[0.5,0.5,0.5]},"thirdperson_righthand":{"rotation":[75,315,0],"translation":[0,2.5,0],"scale":[0.375,0.375,0.375]},"firstperson_righthand":{"rotation":[0,315,0],"translation":[0,0,0],"scale":[0.4,0.4,0.4]}}},"template_skull":{"textures":{"particle":"block/soul_sand"},"display":{"gui":{"rotation":[30,45,0],"translation":[0,3,0],"scale":[1,1,1]},"fixed":{"rotation":[0,180,0],"translation":[0,4,0],"scale":[1,1,1]},"ground":{"rotation":[0,0,0],"translation":[0,3,0],"scale":[0.5,0.5,0.5]},"thirdperson_righthand":{"rotation":[45,45,0],"translation":[0,3,0],"scale":[0.5,0.5,0.5]}}},"template_spawn_egg":{"parent":"item/generated","textures":{"layer0":"item/spawn_egg","layer1":"item/spawn_egg_overlay"}},"tide_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tide_armor_trim_smithing_template"}},"tipped_arrow":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tipped_arrow_head","layer1":"minecraft:item/tipped_arrow_base"}},"tnt_minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tnt_minecart"}},"tooting_goat_horn":{"parent":"item/generated","textures":{"layer0":"item/goat_horn"},"display":{"thirdperson_righthand":{"rotation":[0,-125,0],"translation":[-1,2,2],"scale":[0.5,0.5,0.5]},"thirdperson_lefthand":{"rotation":[0,55,0],"translation":[-1,2,2],"scale":[0.5,0.5,0.5]},"firstperson_righthand":{"rotation":[0,-55,-5],"translation":[-1,-2.5,-7.5]},"firstperson_lefthand":{"rotation":[0,115,5],"translation":[0,-2.5,-7.5]}}},"torch":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/torch"}},"torchflower":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/torchflower"}},"torchflower_seeds":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/torchflower_seeds"}},"totem_of_undying":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/totem_of_undying"}},"trapped_chest":{"parent":"minecraft:item/template_chest","textures":{"particle":"minecraft:block/oak_planks"}},"trial_key":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/trial_key"}},"trident":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/trident"}},"trident_in_hand":{"gui_light":"front","textures":{"particle":"item/trident"},"display":{"thirdperson_righthand":{"rotation":[0,60,0],"translation":[11,17,-2],"scale":[1,1,1]},"thirdperson_lefthand":{"rotation":[0,60,0],"translation":[3,17,12],"scale":[1,1,1]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[-3,17,1],"scale":[1,1,1]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[13,17,1],"scale":[1,1,1]},"gui":{"rotation":[15,-25,-5],"translation":[2,3,0],"scale":[0.65,0.65,0.65]},"fixed":{"rotation":[0,180,0],"translation":[-2,4,-5],"scale":[0.5,0.5,0.5]},"ground":{"rotation":[0,0,0],"translation":[4,4,2],"scale":[0.25,0.25,0.25]}}},"trident_throwing":{"gui_light":"front","textures":{"particle":"item/trident"},"display":{"thirdperson_righthand":{"rotation":[0,90,180],"translation":[8,-17,9],"scale":[1,1,1]},"thirdperson_lefthand":{"rotation":[0,90,180],"translation":[8,-17,-7],"scale":[1,1,1]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[-3,17,1],"scale":[1,1,1]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[13,17,1],"scale":[1,1,1]},"gui":{"rotation":[15,-25,-5],"translation":[2,3,0],"scale":[0.65,0.65,0.65]},"fixed":{"rotation":[0,180,0],"translation":[-2,4,-5],"scale":[0.5,0.5,0.5]},"ground":{"rotation":[0,0,0],"translation":[4,4,2],"scale":[0.25,0.25,0.25]}}},"tripwire_hook":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/tripwire_hook"}},"tropical_fish":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tropical_fish"}},"tropical_fish_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tropical_fish_bucket"}},"tube_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/tube_coral"}},"tube_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/tube_coral_fan"}},"turtle_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_egg"}},"turtle_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet"}},"turtle_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"turtle_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"turtle_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond"}},"turtle_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"turtle_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_gold"}},"turtle_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_iron"}},"turtle_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"turtle_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite"}},"turtle_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"turtle_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"turtle_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"turtle_scute":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_scute"}},"twisting_vines":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/twisting_vines_plant"}},"vex_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/vex_armor_trim_smithing_template"}},"vine":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/vine"}},"ward_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ward_armor_trim_smithing_template"}},"warped_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/warped_door"}},"warped_fungus":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/warped_fungus"}},"warped_fungus_on_a_stick":{"parent":"minecraft:item/handheld_rod","textures":{"layer0":"minecraft:item/warped_fungus_on_a_stick"}},"warped_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/warped_hanging_sign"}},"warped_roots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/warped_roots"}},"warped_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/warped_sign"}},"water_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/water_bucket"}},"wayfinder_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wayfinder_armor_trim_smithing_template"}},"weathered_copper_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/weathered_copper_door"}},"weeping_vines":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/weeping_vines_plant"}},"wheat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wheat"}},"wheat_seeds":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wheat_seeds"}},"white_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/white_wool"}},"white_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/white_bundle"}},"white_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/white_bundle_open_back"}},"white_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/white_bundle_open_front"}},"white_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/white_candle"}},"white_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/white_dye"}},"white_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/white_shulker_box"}},"white_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/white_stained_glass"}},"white_tulip":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/white_tulip"}},"wild_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wild_armor_trim_smithing_template"}},"wind_charge":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wind_charge"}},"wither_rose":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/wither_rose"}},"wolf_armor":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wolf_armor"}},"wolf_armor_dyed":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wolf_armor","layer1":"minecraft:item/wolf_armor_overlay"}},"wooden_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/wooden_axe"}},"wooden_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/wooden_hoe"}},"wooden_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/wooden_pickaxe"}},"wooden_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/wooden_shovel"}},"wooden_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/wooden_sword"}},"writable_book":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/writable_book"}},"written_book":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/written_book"}},"yellow_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/yellow_wool"}},"yellow_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/yellow_bundle"}},"yellow_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/yellow_bundle_open_back"}},"yellow_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/yellow_bundle_open_front"}},"yellow_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/yellow_candle"}},"yellow_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/yellow_dye"}},"yellow_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/yellow_shulker_box"}},"yellow_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/yellow_stained_glass"}}} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/models/item/modern/_list.json b/common-files/src/main/resources/internal/models/item/_list.json similarity index 100% rename from common-files/src/main/resources/internal/models/item/modern/_list.json rename to common-files/src/main/resources/internal/models/item/_list.json diff --git a/common-files/src/main/resources/internal/models/item/modern/_all.json b/common-files/src/main/resources/internal/models/item/modern/_all.json deleted file mode 100644 index 57afab752..000000000 --- a/common-files/src/main/resources/internal/models/item/modern/_all.json +++ /dev/null @@ -1 +0,0 @@ -{"acacia_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/acacia_boat"}},"acacia_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/acacia_chest_boat"}},"acacia_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/acacia_door"}},"acacia_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/acacia_hanging_sign"}},"acacia_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/acacia_sapling"}},"acacia_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/acacia_sign"}},"activator_rail":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/activator_rail"}},"air":{"textures":{"particle":"minecraft:missingno"}},"allay_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/allay_spawn_egg"}},"allium":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/allium"}},"amethyst_bud":{"parent":"minecraft:item/generated","display":{"firstperson_righthand":{"rotation":[0,-90,25],"translation":[0,5,0],"scale":[0.68,0.68,0.68]},"thirdperson_righthand":{"translation":[0,4,1],"scale":[0.55,0.55,0.55]},"head":{"translation":[0,14,-5]},"gui":{"translation":[0,2,0]}}},"amethyst_cluster":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/amethyst_cluster"},"display":{"head":{"translation":[0,14,-5]}}},"amethyst_shard":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/amethyst_shard"}},"angler_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/angler_pottery_sherd"}},"apple":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/apple"}},"archer_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/archer_pottery_sherd"}},"armadillo_scute":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/armadillo_scute"}},"armadillo_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/armadillo_spawn_egg"}},"armor_stand":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/armor_stand"}},"arms_up_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/arms_up_pottery_sherd"}},"arrow":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/arrow"}},"axolotl_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/axolotl_bucket"}},"axolotl_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/axolotl_spawn_egg"}},"azure_bluet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/azure_bluet"}},"baked_potato":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/baked_potato"}},"bamboo":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/bamboo"}},"bamboo_chest_raft":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bamboo_chest_raft"}},"bamboo_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bamboo_door"}},"bamboo_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bamboo_hanging_sign"}},"bamboo_raft":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bamboo_raft"}},"bamboo_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bamboo_sign"}},"barrier":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/barrier"}},"bat_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bat_spawn_egg"}},"bee_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bee_spawn_egg"}},"beef":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/beef"}},"beetroot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/beetroot"}},"beetroot_seeds":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/beetroot_seeds"}},"beetroot_soup":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/beetroot_soup"}},"bell":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bell"}},"big_dripleaf":{"parent":"minecraft:block/big_dripleaf","display":{"gui":{"rotation":[30,225,0],"translation":[0,-2,0],"scale":[0.625,0.625,0.625]},"fixed":{"rotation":[0,0,0],"translation":[0,0,-1],"scale":[0.5,0.5,0.5]},"thirdperson_righthand":{"rotation":[0,0,0],"translation":[0,1,0],"scale":[0.55,0.55,0.55]},"firstperson_righthand":{"rotation":[0,0,0],"translation":[1.13,0,1.13],"scale":[0.68,0.68,0.68]}}},"birch_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/birch_boat"}},"birch_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/birch_chest_boat"}},"birch_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/birch_door"}},"birch_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/birch_hanging_sign"}},"birch_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/birch_sapling"}},"birch_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/birch_sign"}},"black_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/black_wool"}},"black_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/black_bundle"}},"black_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/black_bundle_open_back"}},"black_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/black_bundle_open_front"}},"black_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/black_candle"}},"black_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/black_dye"}},"black_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/black_shulker_box"}},"black_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/black_stained_glass"}},"blade_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blade_pottery_sherd"}},"blaze_powder":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blaze_powder"}},"blaze_rod":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/blaze_rod"}},"blaze_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blaze_spawn_egg"}},"blue_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/blue_wool"}},"blue_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blue_bundle"}},"blue_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/blue_bundle_open_back"}},"blue_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/blue_bundle_open_front"}},"blue_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blue_candle"}},"blue_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blue_dye"}},"blue_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blue_egg"}},"blue_orchid":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/blue_orchid"}},"blue_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/blue_shulker_box"}},"blue_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/blue_stained_glass"}},"bogged_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bogged_spawn_egg"}},"bolt_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bolt_armor_trim_smithing_template"}},"bone":{"parent":"item/handheld","textures":{"layer0":"item/bone"},"display":{"head":{"rotation":[0,0,-45],"translation":[0,-4.5,-6.5],"scale":[1,1,1]}}},"bone_meal":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bone_meal"}},"book":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/book"}},"bordure_indented_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bordure_indented_banner_pattern"}},"bow":{"parent":"item/generated","textures":{"layer0":"item/bow"},"display":{"thirdperson_righthand":{"rotation":[-80,260,-40],"translation":[-1,-2,2.5],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[-80,-280,40],"translation":[-1,-2,2.5],"scale":[0.9,0.9,0.9]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]}}},"bow_pulling_0":{"parent":"minecraft:item/bow","textures":{"layer0":"minecraft:item/bow_pulling_0"}},"bow_pulling_1":{"parent":"minecraft:item/bow","textures":{"layer0":"minecraft:item/bow_pulling_1"}},"bow_pulling_2":{"parent":"minecraft:item/bow","textures":{"layer0":"minecraft:item/bow_pulling_2"}},"bowl":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bowl"}},"brain_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/brain_coral"}},"brain_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/brain_coral_fan"}},"bread":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bread"}},"breeze_rod":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/breeze_rod"}},"breeze_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/breeze_spawn_egg"}},"brewer_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brewer_pottery_sherd"}},"brewing_stand":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brewing_stand"}},"brick":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brick"}},"brown_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/brown_wool"}},"brown_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brown_bundle"}},"brown_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/brown_bundle_open_back"}},"brown_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/brown_bundle_open_front"}},"brown_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brown_candle"}},"brown_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brown_dye"}},"brown_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brown_egg"}},"brown_mushroom":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/brown_mushroom"}},"brown_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/brown_shulker_box"}},"brown_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/brown_stained_glass"}},"brush":{"parent":"item/generated","textures":{"layer0":"item/brush"},"display":{"firstperson_lefthand":{"rotation":[55,-85,0],"translation":[8.0,0.5,-5.5],"scale":[1.0,1.0,1.0]},"thirdperson_righthand":{"rotation":[0,0,45],"translation":[0,4,0],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[0,0,-45],"translation":[0,4,0],"scale":[0.9,0.9,0.9]}}},"brush_brushing_0":{"parent":"item/generated","textures":{"layer0":"item/brush"},"display":{"firstperson_lefthand":{"rotation":[55,-85,0],"translation":[8.0,0.5,-5.5],"scale":[1.0,1.0,1.0]},"thirdperson_righthand":{"rotation":[0,0,0],"translation":[4,2,0],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[0,0,0],"translation":[-4,2,0],"scale":[0.9,0.9,0.9]}}},"brush_brushing_1":{"parent":"item/generated","textures":{"layer0":"item/brush"},"display":{"firstperson_lefthand":{"rotation":[55,-85,0],"translation":[8.0,0.5,-5.5],"scale":[1.0,1.0,1.0]},"thirdperson_righthand":{"rotation":[0,0,45],"translation":[0,4,0],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[0,0,-45],"translation":[0,4,0],"scale":[0.9,0.9,0.9]}}},"brush_brushing_2":{"parent":"item/generated","textures":{"layer0":"item/brush"},"display":{"firstperson_lefthand":{"rotation":[55,-85,0],"translation":[8.0,0.5,-5.5],"scale":[1.0,1.0,1.0]},"thirdperson_righthand":{"rotation":[0,0,90],"translation":[-4,2,0],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[0,0,-90],"translation":[4,2,0],"scale":[0.9,0.9,0.9]}}},"bubble_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/bubble_coral"}},"bubble_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/bubble_coral_fan"}},"bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bucket"}},"bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/bundle"}},"bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/bundle_open_back"}},"bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/bundle_open_front"}},"burn_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/burn_pottery_sherd"}},"bush":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/bush"}},"cactus_flower":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/cactus_flower"}},"cake":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cake"}},"camel_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/camel_spawn_egg"}},"campfire":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/campfire"}},"candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/candle"}},"carrot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/carrot"}},"carrot_on_a_stick":{"parent":"minecraft:item/handheld_rod","textures":{"layer0":"minecraft:item/carrot_on_a_stick"}},"cat_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cat_spawn_egg"}},"cauldron":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cauldron"}},"cave_spider_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cave_spider_spawn_egg"}},"chain":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chain"}},"chainmail_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots"}},"chainmail_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_amethyst"}},"chainmail_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_copper"}},"chainmail_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_diamond"}},"chainmail_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_emerald"}},"chainmail_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_gold"}},"chainmail_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_iron"}},"chainmail_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_lapis"}},"chainmail_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_netherite"}},"chainmail_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_quartz"}},"chainmail_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_redstone"}},"chainmail_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_boots","layer1":"minecraft:trims/items/boots_trim_resin"}},"chainmail_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate"}},"chainmail_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_amethyst"}},"chainmail_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_copper"}},"chainmail_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_diamond"}},"chainmail_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_emerald"}},"chainmail_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_gold"}},"chainmail_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_iron"}},"chainmail_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_lapis"}},"chainmail_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_netherite"}},"chainmail_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_quartz"}},"chainmail_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_redstone"}},"chainmail_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_chestplate","layer1":"minecraft:trims/items/chestplate_trim_resin"}},"chainmail_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet"}},"chainmail_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"chainmail_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"chainmail_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond"}},"chainmail_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"chainmail_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_gold"}},"chainmail_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_iron"}},"chainmail_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"chainmail_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite"}},"chainmail_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"chainmail_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"chainmail_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"chainmail_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings"}},"chainmail_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_amethyst"}},"chainmail_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_copper"}},"chainmail_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_diamond"}},"chainmail_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_emerald"}},"chainmail_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_gold"}},"chainmail_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_iron"}},"chainmail_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_lapis"}},"chainmail_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_netherite"}},"chainmail_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_quartz"}},"chainmail_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_redstone"}},"chainmail_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chainmail_leggings","layer1":"minecraft:trims/items/leggings_trim_resin"}},"charcoal":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/charcoal"}},"cherry_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cherry_boat"}},"cherry_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cherry_chest_boat"}},"cherry_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cherry_door"}},"cherry_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cherry_hanging_sign"}},"cherry_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/cherry_sapling"}},"cherry_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cherry_sign"}},"chest":{"parent":"minecraft:item/template_chest","textures":{"particle":"minecraft:block/oak_planks"}},"chest_minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chest_minecart"}},"chicken":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chicken"}},"chicken_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chicken_spawn_egg"}},"chorus_fruit":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/chorus_fruit"}},"clay_ball":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clay_ball"}},"clock_00":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_00"}},"clock_01":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_01"}},"clock_02":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_02"}},"clock_03":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_03"}},"clock_04":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_04"}},"clock_05":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_05"}},"clock_06":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_06"}},"clock_07":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_07"}},"clock_08":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_08"}},"clock_09":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_09"}},"clock_10":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_10"}},"clock_11":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_11"}},"clock_12":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_12"}},"clock_13":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_13"}},"clock_14":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_14"}},"clock_15":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_15"}},"clock_16":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_16"}},"clock_17":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_17"}},"clock_18":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_18"}},"clock_19":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_19"}},"clock_20":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_20"}},"clock_21":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_21"}},"clock_22":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_22"}},"clock_23":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_23"}},"clock_24":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_24"}},"clock_25":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_25"}},"clock_26":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_26"}},"clock_27":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_27"}},"clock_28":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_28"}},"clock_29":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_29"}},"clock_30":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_30"}},"clock_31":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_31"}},"clock_32":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_32"}},"clock_33":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_33"}},"clock_34":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_34"}},"clock_35":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_35"}},"clock_36":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_36"}},"clock_37":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_37"}},"clock_38":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_38"}},"clock_39":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_39"}},"clock_40":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_40"}},"clock_41":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_41"}},"clock_42":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_42"}},"clock_43":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_43"}},"clock_44":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_44"}},"clock_45":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_45"}},"clock_46":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_46"}},"clock_47":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_47"}},"clock_48":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_48"}},"clock_49":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_49"}},"clock_50":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_50"}},"clock_51":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_51"}},"clock_52":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_52"}},"clock_53":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_53"}},"clock_54":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_54"}},"clock_55":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_55"}},"clock_56":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_56"}},"clock_57":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_57"}},"clock_58":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_58"}},"clock_59":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_59"}},"clock_60":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_60"}},"clock_61":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_61"}},"clock_62":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_62"}},"clock_63":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/clock_63"}},"closed_eyeblossom":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/closed_eyeblossom"}},"coal":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/coal"}},"coast_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/coast_armor_trim_smithing_template"}},"cobweb":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/cobweb"}},"cocoa_beans":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cocoa_beans"}},"cod":{"parent":"item/generated","textures":{"layer0":"item/cod"},"display":{"head":{"rotation":[0,90,-60],"translation":[-7,-4,-7],"scale":[0.8,0.8,0.8]}}},"cod_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cod_bucket"}},"cod_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cod_spawn_egg"}},"command_block_minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/command_block_minecart"}},"comparator":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/comparator"}},"compass_00":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_00"}},"compass_01":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_01"}},"compass_02":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_02"}},"compass_03":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_03"}},"compass_04":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_04"}},"compass_05":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_05"}},"compass_06":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_06"}},"compass_07":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_07"}},"compass_08":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_08"}},"compass_09":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_09"}},"compass_10":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_10"}},"compass_11":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_11"}},"compass_12":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_12"}},"compass_13":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_13"}},"compass_14":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_14"}},"compass_15":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_15"}},"compass_16":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_16"}},"compass_17":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_17"}},"compass_18":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_18"}},"compass_19":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_19"}},"compass_20":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_20"}},"compass_21":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_21"}},"compass_22":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_22"}},"compass_23":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_23"}},"compass_24":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_24"}},"compass_25":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_25"}},"compass_26":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_26"}},"compass_27":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_27"}},"compass_28":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_28"}},"compass_29":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_29"}},"compass_30":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_30"}},"compass_31":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/compass_31"}},"conduit":{"textures":{"particle":"block/conduit"},"display":{"gui":{"rotation":[30,45,0],"translation":[0,0,0],"scale":[1.0,1.0,1.0]},"ground":{"rotation":[0,0,0],"translation":[0,3,0],"scale":[0.5,0.5,0.5]},"head":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[1,1,1]},"fixed":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[1,1,1]},"thirdperson_righthand":{"rotation":[75,315,0],"translation":[0,2.5,0],"scale":[0.5,0.5,0.5]},"firstperson_righthand":{"rotation":[0,315,0],"translation":[0,0,0],"scale":[0.8,0.8,0.8]}}},"cooked_beef":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_beef"}},"cooked_chicken":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_chicken"}},"cooked_cod":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_cod"}},"cooked_mutton":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_mutton"}},"cooked_porkchop":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_porkchop"}},"cooked_rabbit":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_rabbit"}},"cooked_salmon":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cooked_salmon"}},"cookie":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cookie"}},"copper_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/copper_door"}},"copper_ingot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/copper_ingot"}},"cornflower":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/cornflower"}},"cow_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cow_spawn_egg"}},"creaking_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/creaking_spawn_egg"}},"creeper_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/creeper_banner_pattern"}},"creeper_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/creeper_spawn_egg"}},"crimson_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/crimson_door"}},"crimson_fungus":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/crimson_fungus"}},"crimson_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/crimson_hanging_sign"}},"crimson_roots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/crimson_roots"}},"crimson_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/crimson_sign"}},"crossbow":{"parent":"item/generated","textures":{"layer0":"item/crossbow_standby"},"display":{"thirdperson_righthand":{"rotation":[-90,0,-60],"translation":[2,0.1,-3],"scale":[0.9,0.9,0.9]},"thirdperson_lefthand":{"rotation":[-90,0,30],"translation":[2,0.1,-3],"scale":[0.9,0.9,0.9]},"firstperson_righthand":{"rotation":[-90,0,-55],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]},"firstperson_lefthand":{"rotation":[-90,0,35],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]}}},"crossbow_arrow":{"parent":"minecraft:item/crossbow","textures":{"layer0":"minecraft:item/crossbow_arrow"}},"crossbow_firework":{"parent":"minecraft:item/crossbow","textures":{"layer0":"minecraft:item/crossbow_firework"}},"crossbow_pulling_0":{"parent":"minecraft:item/crossbow","textures":{"layer0":"minecraft:item/crossbow_pulling_0"}},"crossbow_pulling_1":{"parent":"minecraft:item/crossbow","textures":{"layer0":"minecraft:item/crossbow_pulling_1"}},"crossbow_pulling_2":{"parent":"minecraft:item/crossbow","textures":{"layer0":"minecraft:item/crossbow_pulling_2"}},"cyan_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/cyan_wool"}},"cyan_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cyan_bundle"}},"cyan_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/cyan_bundle_open_back"}},"cyan_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/cyan_bundle_open_front"}},"cyan_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cyan_candle"}},"cyan_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cyan_dye"}},"cyan_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/cyan_shulker_box"}},"cyan_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/cyan_stained_glass"}},"dandelion":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dandelion"}},"danger_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/danger_pottery_sherd"}},"dark_oak_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dark_oak_boat"}},"dark_oak_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dark_oak_chest_boat"}},"dark_oak_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dark_oak_door"}},"dark_oak_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dark_oak_hanging_sign"}},"dark_oak_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dark_oak_sapling"}},"dark_oak_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dark_oak_sign"}},"dead_brain_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_brain_coral"}},"dead_brain_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_brain_coral_fan"}},"dead_bubble_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_bubble_coral"}},"dead_bubble_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_bubble_coral_fan"}},"dead_bush":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_bush"}},"dead_fire_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_fire_coral"}},"dead_fire_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_fire_coral_fan"}},"dead_horn_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_horn_coral"}},"dead_horn_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_horn_coral_fan"}},"dead_tube_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_tube_coral"}},"dead_tube_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/dead_tube_coral_fan"}},"debug_stick":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stick"}},"decorated_pot":{"gui_light":"front","textures":{"particle":"entity/decorated_pot/decorated_pot_side"},"display":{"thirdperson_righthand":{"rotation":[0,90,0],"translation":[0,2,0.5],"scale":[0.375,0.375,0.375]},"firstperson_righthand":{"rotation":[0,90,0],"translation":[0,0,0],"scale":[0.375,0.375,0.375]},"gui":{"rotation":[30,45,0],"translation":[0,0,0],"scale":[0.60,0.60,0.60]},"ground":{"rotation":[0,0,0],"translation":[0,1,0],"scale":[0.25,0.25,0.25]},"head":{"rotation":[0,180,0],"translation":[0,16,0],"scale":[1.5,1.5,1.5]},"fixed":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[0.5,0.5,0.5]}}},"detector_rail":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/detector_rail"}},"diamond":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond"}},"diamond_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/diamond_axe"}},"diamond_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots"}},"diamond_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_amethyst"}},"diamond_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_copper"}},"diamond_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_diamond_darker"}},"diamond_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_emerald"}},"diamond_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_gold"}},"diamond_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_iron"}},"diamond_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_lapis"}},"diamond_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_netherite"}},"diamond_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_quartz"}},"diamond_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_redstone"}},"diamond_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_boots","layer1":"minecraft:trims/items/boots_trim_resin"}},"diamond_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate"}},"diamond_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_amethyst"}},"diamond_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_copper"}},"diamond_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_diamond_darker"}},"diamond_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_emerald"}},"diamond_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_gold"}},"diamond_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_iron"}},"diamond_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_lapis"}},"diamond_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_netherite"}},"diamond_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_quartz"}},"diamond_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_redstone"}},"diamond_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_chestplate","layer1":"minecraft:trims/items/chestplate_trim_resin"}},"diamond_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet"}},"diamond_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"diamond_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"diamond_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond_darker"}},"diamond_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"diamond_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_gold"}},"diamond_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_iron"}},"diamond_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"diamond_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite"}},"diamond_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"diamond_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"diamond_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"diamond_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/diamond_hoe"}},"diamond_horse_armor":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_horse_armor"}},"diamond_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings"}},"diamond_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_amethyst"}},"diamond_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_copper"}},"diamond_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_diamond_darker"}},"diamond_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_emerald"}},"diamond_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_gold"}},"diamond_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_iron"}},"diamond_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_lapis"}},"diamond_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_netherite"}},"diamond_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_quartz"}},"diamond_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_redstone"}},"diamond_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/diamond_leggings","layer1":"minecraft:trims/items/leggings_trim_resin"}},"diamond_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/diamond_pickaxe"}},"diamond_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/diamond_shovel"}},"diamond_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/diamond_sword"}},"disc_fragment_5":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/disc_fragment_5"}},"dolphin_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dolphin_spawn_egg"}},"donkey_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/donkey_spawn_egg"}},"dragon_breath":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dragon_breath"}},"dragon_head":{"parent":"item/template_skull","display":{"gui":{"translation":[-2,2,0],"rotation":[30,45,0],"scale":[0.6,0.6,0.6]},"thirdperson_righthand":{"rotation":[0,180,0],"translation":[0,-1,2],"scale":[0.5,0.5,0.5]}}},"dried_kelp":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dried_kelp"}},"drowned_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/drowned_spawn_egg"}},"dune_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/dune_armor_trim_smithing_template"}},"echo_shard":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/echo_shard"}},"egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/egg"}},"elder_guardian_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/elder_guardian_spawn_egg"}},"elytra":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/elytra"}},"elytra_broken":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/elytra_broken"}},"emerald":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/emerald"}},"enchanted_book":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/enchanted_book"}},"enchanted_golden_apple":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_apple"}},"end_crystal":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/end_crystal"}},"ender_chest":{"parent":"minecraft:item/template_chest","textures":{"particle":"minecraft:block/obsidian"}},"ender_dragon_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ender_dragon_spawn_egg"}},"ender_eye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ender_eye"}},"ender_pearl":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ender_pearl"}},"enderman_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/enderman_spawn_egg"}},"endermite_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/endermite_spawn_egg"}},"evoker_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/evoker_spawn_egg"}},"experience_bottle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/experience_bottle"}},"explorer_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/explorer_pottery_sherd"}},"exposed_copper_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/exposed_copper_door"}},"eye_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/eye_armor_trim_smithing_template"}},"feather":{"parent":"item/generated","textures":{"layer0":"item/feather"},"display":{"head":{"rotation":[0,0,45],"translation":[-1,13,7],"scale":[1,1,1]}}},"fermented_spider_eye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/fermented_spider_eye"}},"fern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/fern"}},"field_masoned_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/field_masoned_banner_pattern"}},"filled_map":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/filled_map","layer1":"minecraft:item/filled_map_markings"}},"fire_charge":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/fire_charge"}},"fire_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/fire_coral"}},"fire_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/fire_coral_fan"}},"firefly_bush":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/firefly_bush"}},"firework_rocket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/firework_rocket"}},"firework_star":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/firework_star","layer1":"minecraft:item/firework_star_overlay"}},"fishing_rod":{"parent":"minecraft:item/handheld_rod","textures":{"layer0":"minecraft:item/fishing_rod"}},"fishing_rod_cast":{"parent":"minecraft:item/handheld_rod","textures":{"layer0":"minecraft:item/fishing_rod_cast"}},"flint":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flint"}},"flint_and_steel":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flint_and_steel"}},"flow_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flow_armor_trim_smithing_template"}},"flow_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flow_banner_pattern"}},"flow_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flow_pottery_sherd"}},"flower_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flower_banner_pattern"}},"flower_pot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/flower_pot"}},"fox_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/fox_spawn_egg"}},"friend_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/friend_pottery_sherd"}},"frog_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/frog_spawn_egg"}},"frogspawn":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/frogspawn"}},"furnace_minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/furnace_minecart"}},"generated":{"parent":"builtin/generated","gui_light":"front","display":{"ground":{"rotation":[0,0,0],"translation":[0,2,0],"scale":[0.5,0.5,0.5]},"head":{"rotation":[0,180,0],"translation":[0,13,7],"scale":[1,1,1]},"thirdperson_righthand":{"rotation":[0,0,0],"translation":[0,3,1],"scale":[0.55,0.55,0.55]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]},"fixed":{"rotation":[0,180,0],"scale":[1,1,1]}}},"ghast_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ghast_spawn_egg"}},"ghast_tear":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ghast_tear"}},"glass_bottle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glass_bottle"}},"glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/glass"}},"glistering_melon_slice":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glistering_melon_slice"}},"globe_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/globe_banner_pattern"}},"glow_berries":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glow_berries"}},"glow_ink_sac":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glow_ink_sac"}},"glow_item_frame":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glow_item_frame"}},"glow_lichen":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/glow_lichen"}},"glow_squid_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glow_squid_spawn_egg"}},"glowstone_dust":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/glowstone_dust"}},"goat_horn":{"parent":"item/generated","textures":{"layer0":"item/goat_horn"},"display":{"thirdperson_righthand":{"rotation":[0,180,0],"translation":[0,3,1],"scale":[0.55,0.55,0.55]},"thirdperson_lefthand":{"rotation":[0,0,0],"translation":[0,3,1],"scale":[0.55,0.55,0.55]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]}}},"goat_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/goat_spawn_egg"}},"gold_ingot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gold_ingot"}},"gold_nugget":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gold_nugget"}},"golden_apple":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_apple"}},"golden_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/golden_axe"}},"golden_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots"}},"golden_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_amethyst"}},"golden_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_copper"}},"golden_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_diamond"}},"golden_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_emerald"}},"golden_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_gold_darker"}},"golden_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_iron"}},"golden_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_lapis"}},"golden_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_netherite"}},"golden_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_quartz"}},"golden_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_redstone"}},"golden_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_boots","layer1":"minecraft:trims/items/boots_trim_resin"}},"golden_carrot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_carrot"}},"golden_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate"}},"golden_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_amethyst"}},"golden_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_copper"}},"golden_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_diamond"}},"golden_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_emerald"}},"golden_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_gold_darker"}},"golden_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_iron"}},"golden_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_lapis"}},"golden_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_netherite"}},"golden_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_quartz"}},"golden_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_redstone"}},"golden_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_chestplate","layer1":"minecraft:trims/items/chestplate_trim_resin"}},"golden_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet"}},"golden_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"golden_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"golden_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond"}},"golden_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"golden_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_gold_darker"}},"golden_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_iron"}},"golden_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"golden_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite"}},"golden_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"golden_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"golden_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"golden_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/golden_hoe"}},"golden_horse_armor":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_horse_armor"}},"golden_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings"}},"golden_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_amethyst"}},"golden_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_copper"}},"golden_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_diamond"}},"golden_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_emerald"}},"golden_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_gold_darker"}},"golden_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_iron"}},"golden_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_lapis"}},"golden_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_netherite"}},"golden_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_quartz"}},"golden_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_redstone"}},"golden_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/golden_leggings","layer1":"minecraft:trims/items/leggings_trim_resin"}},"golden_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/golden_pickaxe"}},"golden_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/golden_shovel"}},"golden_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/golden_sword"}},"gray_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/gray_wool"}},"gray_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gray_bundle"}},"gray_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/gray_bundle_open_back"}},"gray_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/gray_bundle_open_front"}},"gray_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gray_candle"}},"gray_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gray_dye"}},"gray_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/gray_shulker_box"}},"gray_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/gray_stained_glass"}},"green_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/green_wool"}},"green_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/green_bundle"}},"green_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/green_bundle_open_back"}},"green_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/green_bundle_open_front"}},"green_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/green_candle"}},"green_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/green_dye"}},"green_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/green_shulker_box"}},"green_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/green_stained_glass"}},"guardian_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/guardian_spawn_egg"}},"gunpowder":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gunpowder"}},"guster_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/guster_banner_pattern"}},"guster_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/guster_pottery_sherd"}},"handheld":{"parent":"item/generated","display":{"thirdperson_righthand":{"rotation":[0,-90,55],"translation":[0,4.0,0.5],"scale":[0.85,0.85,0.85]},"thirdperson_lefthand":{"rotation":[0,90,-55],"translation":[0,4.0,0.5],"scale":[0.85,0.85,0.85]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[1.13,3.2,1.13],"scale":[0.68,0.68,0.68]}}},"handheld_mace":{"parent":"item/handheld","display":{"thirdperson_righthand":{"rotation":[0,-90,55],"translation":[0,4.0,1],"scale":[1,1,1]},"thirdperson_lefthand":{"rotation":[0,90,-55],"translation":[0,4.0,1],"scale":[1,1,1]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[0,3,0.8],"scale":[0.9,0.9,0.9]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[0,3,0.8],"scale":[0.9,0.9,0.9]}}},"handheld_rod":{"parent":"item/handheld","display":{"thirdperson_righthand":{"rotation":[0,90,55],"translation":[0,4.0,2.5],"scale":[0.85,0.85,0.85]},"thirdperson_lefthand":{"rotation":[0,-90,-55],"translation":[0,4.0,2.5],"scale":[0.85,0.85,0.85]},"firstperson_righthand":{"rotation":[0,90,25],"translation":[0,1.6,0.8],"scale":[0.68,0.68,0.68]},"firstperson_lefthand":{"rotation":[0,-90,-25],"translation":[0,1.6,0.8],"scale":[0.68,0.68,0.68]}}},"hanging_roots":{"parent":"item/generated","textures":{"layer0":"minecraft:block/hanging_roots"},"display":{"thirdperson_righthand":{"rotation":[0,0,0],"translation":[0,0,1],"scale":[0.55,0.55,0.55]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[1.13,0,1.13],"scale":[0.68,0.68,0.68]}}},"heart_of_the_sea":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/heart_of_the_sea"}},"heart_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/heart_pottery_sherd"}},"heartbreak_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/heartbreak_pottery_sherd"}},"hoglin_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/hoglin_spawn_egg"}},"honey_bottle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/honey_bottle"}},"honeycomb":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/honeycomb"}},"hopper":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/hopper"}},"hopper_minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/hopper_minecart"}},"horn_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/horn_coral"}},"horn_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/horn_coral_fan"}},"horse_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/horse_spawn_egg"}},"host_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/host_armor_trim_smithing_template"}},"howl_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/howl_pottery_sherd"}},"husk_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/husk_spawn_egg"}},"ink_sac":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ink_sac"}},"iron_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/iron_axe"}},"iron_bars":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/iron_bars"}},"iron_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots"}},"iron_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_amethyst"}},"iron_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_copper"}},"iron_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_diamond"}},"iron_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_emerald"}},"iron_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_gold"}},"iron_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_iron_darker"}},"iron_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_lapis"}},"iron_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_netherite"}},"iron_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_quartz"}},"iron_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_redstone"}},"iron_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_boots","layer1":"minecraft:trims/items/boots_trim_resin"}},"iron_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate"}},"iron_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_amethyst"}},"iron_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_copper"}},"iron_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_diamond"}},"iron_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_emerald"}},"iron_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_gold"}},"iron_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_iron_darker"}},"iron_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_lapis"}},"iron_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_netherite"}},"iron_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_quartz"}},"iron_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_redstone"}},"iron_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_chestplate","layer1":"minecraft:trims/items/chestplate_trim_resin"}},"iron_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_door"}},"iron_golem_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_golem_spawn_egg"}},"iron_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet"}},"iron_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"iron_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"iron_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond"}},"iron_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"iron_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_gold"}},"iron_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_iron_darker"}},"iron_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"iron_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite"}},"iron_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"iron_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"iron_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"iron_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/iron_hoe"}},"iron_horse_armor":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_horse_armor"}},"iron_ingot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_ingot"}},"iron_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings"}},"iron_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_amethyst"}},"iron_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_copper"}},"iron_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_diamond"}},"iron_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_emerald"}},"iron_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_gold"}},"iron_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_iron_darker"}},"iron_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_lapis"}},"iron_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_netherite"}},"iron_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_quartz"}},"iron_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_redstone"}},"iron_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_leggings","layer1":"minecraft:trims/items/leggings_trim_resin"}},"iron_nugget":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/iron_nugget"}},"iron_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/iron_pickaxe"}},"iron_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/iron_shovel"}},"iron_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/iron_sword"}},"item_frame":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/item_frame"}},"jungle_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/jungle_boat"}},"jungle_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/jungle_chest_boat"}},"jungle_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/jungle_door"}},"jungle_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/jungle_hanging_sign"}},"jungle_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/jungle_sapling"}},"jungle_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/jungle_sign"}},"kelp":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/kelp"}},"knowledge_book":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/knowledge_book"}},"ladder":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/ladder"}},"lantern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lantern"}},"lapis_lazuli":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lapis_lazuli"}},"large_amethyst_bud":{"parent":"item/amethyst_bud","textures":{"layer0":"minecraft:block/large_amethyst_bud"},"display":{"fixed":{"translation":[0,4,0]}}},"large_fern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/large_fern_top"}},"lava_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lava_bucket"}},"lead":{"parent":"item/generated","textures":{"layer0":"item/lead"},"display":{"head":{"rotation":[0,0,0],"translation":[2.75,-2.75,-6.5],"scale":[0.8,0.8,0.8]}}},"leaf_litter":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leaf_litter"}},"leather":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather"}},"leather_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay"}},"leather_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_amethyst"}},"leather_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_copper"}},"leather_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_diamond"}},"leather_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_emerald"}},"leather_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_gold"}},"leather_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_iron"}},"leather_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_lapis"}},"leather_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_netherite"}},"leather_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_quartz"}},"leather_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_redstone"}},"leather_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_boots","layer1":"minecraft:item/leather_boots_overlay","layer2":"minecraft:trims/items/boots_trim_resin"}},"leather_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay"}},"leather_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_amethyst"}},"leather_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_copper"}},"leather_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_diamond"}},"leather_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_emerald"}},"leather_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_gold"}},"leather_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_iron"}},"leather_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_lapis"}},"leather_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_netherite"}},"leather_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_quartz"}},"leather_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_redstone"}},"leather_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_chestplate","layer1":"minecraft:item/leather_chestplate_overlay","layer2":"minecraft:trims/items/chestplate_trim_resin"}},"leather_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay"}},"leather_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_amethyst"}},"leather_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_copper"}},"leather_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_diamond"}},"leather_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_emerald"}},"leather_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_gold"}},"leather_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_iron"}},"leather_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_lapis"}},"leather_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_netherite"}},"leather_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_quartz"}},"leather_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_redstone"}},"leather_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_helmet","layer1":"minecraft:item/leather_helmet_overlay","layer2":"minecraft:trims/items/helmet_trim_resin"}},"leather_horse_armor":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_horse_armor"}},"leather_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay"}},"leather_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_amethyst"}},"leather_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_copper"}},"leather_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_diamond"}},"leather_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_emerald"}},"leather_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_gold"}},"leather_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_iron"}},"leather_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_lapis"}},"leather_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_netherite"}},"leather_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_quartz"}},"leather_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_redstone"}},"leather_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/leather_leggings","layer1":"minecraft:item/leather_leggings_overlay","layer2":"minecraft:trims/items/leggings_trim_resin"}},"lever":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/lever"}},"light":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light"}},"light_00":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_00"}},"light_01":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_01"}},"light_02":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_02"}},"light_03":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_03"}},"light_04":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_04"}},"light_05":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_05"}},"light_06":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_06"}},"light_07":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_07"}},"light_08":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_08"}},"light_09":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_09"}},"light_10":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_10"}},"light_11":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_11"}},"light_12":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_12"}},"light_13":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_13"}},"light_14":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_14"}},"light_15":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_15"}},"light_blue_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/light_blue_wool"}},"light_blue_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_blue_bundle"}},"light_blue_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/light_blue_bundle_open_back"}},"light_blue_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/light_blue_bundle_open_front"}},"light_blue_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_blue_candle"}},"light_blue_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_blue_dye"}},"light_blue_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/light_blue_shulker_box"}},"light_blue_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/light_blue_stained_glass"}},"light_gray_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/light_gray_wool"}},"light_gray_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_gray_bundle"}},"light_gray_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/light_gray_bundle_open_back"}},"light_gray_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/light_gray_bundle_open_front"}},"light_gray_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_gray_candle"}},"light_gray_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_gray_dye"}},"light_gray_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/light_gray_shulker_box"}},"light_gray_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/light_gray_stained_glass"}},"lilac":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/lilac_top"}},"lily_of_the_valley":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/lily_of_the_valley"}},"lily_pad":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/lily_pad"}},"lime_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/lime_wool"}},"lime_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lime_bundle"}},"lime_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/lime_bundle_open_back"}},"lime_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/lime_bundle_open_front"}},"lime_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lime_candle"}},"lime_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lime_dye"}},"lime_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/lime_shulker_box"}},"lime_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/lime_stained_glass"}},"lingering_potion":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/potion_overlay","layer1":"minecraft:item/lingering_potion"}},"llama_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/llama_spawn_egg"}},"mace":{"parent":"minecraft:item/handheld_mace","textures":{"layer0":"minecraft:item/mace"}},"magenta_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/magenta_wool"}},"magenta_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magenta_bundle"}},"magenta_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/magenta_bundle_open_back"}},"magenta_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/magenta_bundle_open_front"}},"magenta_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magenta_candle"}},"magenta_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magenta_dye"}},"magenta_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/magenta_shulker_box"}},"magenta_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/magenta_stained_glass"}},"magma_cream":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magma_cream"}},"magma_cube_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magma_cube_spawn_egg"}},"mangrove_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_boat"}},"mangrove_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_chest_boat"}},"mangrove_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_door"}},"mangrove_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_hanging_sign"}},"mangrove_propagule":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_propagule"}},"mangrove_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mangrove_sign"}},"map":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/map"}},"medium_amethyst_bud":{"parent":"item/amethyst_bud","textures":{"layer0":"minecraft:block/medium_amethyst_bud"},"display":{"fixed":{"translation":[0,6,0]}}},"melon_seeds":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/melon_seeds"}},"melon_slice":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/melon_slice"}},"milk_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/milk_bucket"}},"minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/minecart"}},"miner_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/miner_pottery_sherd"}},"mojang_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mojang_banner_pattern"}},"mooshroom_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mooshroom_spawn_egg"}},"mourner_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mourner_pottery_sherd"}},"mule_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mule_spawn_egg"}},"mushroom_stew":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mushroom_stew"}},"music_disc_11":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_11"}},"music_disc_13":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_13"}},"music_disc_5":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_5"}},"music_disc_blocks":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_blocks"}},"music_disc_cat":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_cat"}},"music_disc_chirp":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_chirp"}},"music_disc_creator":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_creator"}},"music_disc_creator_music_box":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_creator_music_box"}},"music_disc_far":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_far"}},"music_disc_mall":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_mall"}},"music_disc_mellohi":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_mellohi"}},"music_disc_otherside":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_otherside"}},"music_disc_pigstep":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_pigstep"}},"music_disc_precipice":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_precipice"}},"music_disc_relic":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_relic"}},"music_disc_stal":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_stal"}},"music_disc_strad":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_strad"}},"music_disc_wait":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_wait"}},"music_disc_ward":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_ward"}},"mutton":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/mutton"}},"name_tag":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/name_tag"}},"nautilus_shell":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/nautilus_shell"}},"nether_brick":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/nether_brick"}},"nether_sprouts":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/nether_sprouts"}},"nether_star":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/nether_star"}},"nether_wart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/nether_wart"}},"netherite_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/netherite_axe"}},"netherite_boots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots"}},"netherite_boots_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_amethyst"}},"netherite_boots_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_copper"}},"netherite_boots_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_diamond"}},"netherite_boots_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_emerald"}},"netherite_boots_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_gold"}},"netherite_boots_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_iron"}},"netherite_boots_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_lapis"}},"netherite_boots_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_netherite_darker"}},"netherite_boots_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_quartz"}},"netherite_boots_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_redstone"}},"netherite_boots_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_boots","layer1":"minecraft:trims/items/boots_trim_resin"}},"netherite_chestplate":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate"}},"netherite_chestplate_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_amethyst"}},"netherite_chestplate_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_copper"}},"netherite_chestplate_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_diamond"}},"netherite_chestplate_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_emerald"}},"netherite_chestplate_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_gold"}},"netherite_chestplate_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_iron"}},"netherite_chestplate_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_lapis"}},"netherite_chestplate_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_netherite_darker"}},"netherite_chestplate_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_quartz"}},"netherite_chestplate_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_redstone"}},"netherite_chestplate_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_chestplate","layer1":"minecraft:trims/items/chestplate_trim_resin"}},"netherite_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet"}},"netherite_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"netherite_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"netherite_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond"}},"netherite_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"netherite_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_gold"}},"netherite_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_iron"}},"netherite_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"netherite_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite_darker"}},"netherite_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"netherite_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"netherite_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"netherite_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/netherite_hoe"}},"netherite_ingot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_ingot"}},"netherite_leggings":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings"}},"netherite_leggings_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_amethyst"}},"netherite_leggings_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_copper"}},"netherite_leggings_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_diamond"}},"netherite_leggings_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_emerald"}},"netherite_leggings_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_gold"}},"netherite_leggings_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_iron"}},"netherite_leggings_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_lapis"}},"netherite_leggings_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_netherite_darker"}},"netherite_leggings_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_quartz"}},"netherite_leggings_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_redstone"}},"netherite_leggings_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_leggings","layer1":"minecraft:trims/items/leggings_trim_resin"}},"netherite_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/netherite_pickaxe"}},"netherite_scrap":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_scrap"}},"netherite_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/netherite_shovel"}},"netherite_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/netherite_sword"}},"netherite_upgrade_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/netherite_upgrade_smithing_template"}},"oak_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oak_boat"}},"oak_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oak_chest_boat"}},"oak_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oak_door"}},"oak_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oak_hanging_sign"}},"oak_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/oak_sapling"}},"oak_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oak_sign"}},"ocelot_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ocelot_spawn_egg"}},"ominous_bottle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ominous_bottle"}},"ominous_trial_key":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ominous_trial_key"}},"open_eyeblossom":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/open_eyeblossom","layer1":"minecraft:block/open_eyeblossom_emissive"}},"orange_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/orange_wool"}},"orange_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/orange_bundle"}},"orange_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/orange_bundle_open_back"}},"orange_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/orange_bundle_open_front"}},"orange_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/orange_candle"}},"orange_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/orange_dye"}},"orange_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/orange_shulker_box"}},"orange_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/orange_stained_glass"}},"orange_tulip":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/orange_tulip"}},"oxeye_daisy":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/oxeye_daisy"}},"oxidized_copper_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/oxidized_copper_door"}},"painting":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/painting"}},"pale_hanging_moss":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/pale_hanging_moss"}},"pale_oak_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pale_oak_boat"}},"pale_oak_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pale_oak_chest_boat"}},"pale_oak_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pale_oak_door"}},"pale_oak_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pale_oak_hanging_sign"}},"pale_oak_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/pale_oak_sapling"}},"pale_oak_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pale_oak_sign"}},"panda_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/panda_spawn_egg"}},"paper":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/paper"}},"parrot_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/parrot_spawn_egg"}},"peony":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/peony_top"}},"phantom_membrane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/phantom_membrane"}},"phantom_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/phantom_spawn_egg"}},"pig_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pig_spawn_egg"}},"piglin_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/piglin_banner_pattern"}},"piglin_brute_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/piglin_brute_spawn_egg"}},"piglin_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/piglin_spawn_egg"}},"pillager_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pillager_spawn_egg"}},"pink_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/pink_wool"}},"pink_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pink_bundle"}},"pink_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/pink_bundle_open_back"}},"pink_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/pink_bundle_open_front"}},"pink_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pink_candle"}},"pink_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pink_dye"}},"pink_petals":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pink_petals"}},"pink_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/pink_shulker_box"}},"pink_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/pink_stained_glass"}},"pink_tulip":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/pink_tulip"}},"pitcher_plant":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pitcher_plant"}},"pitcher_pod":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pitcher_pod"}},"plenty_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/plenty_pottery_sherd"}},"pointed_dripstone":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pointed_dripstone"},"display":{"thirdperson_righthand":{"rotation":[0,100,0],"translation":[-1,-1,0],"scale":[0.9,0.9,0.9]},"firstperson_righthand":{"rotation":[0,100,0],"translation":[0,-2,0],"scale":[0.9,0.9,0.9]}}},"poisonous_potato":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/poisonous_potato"}},"polar_bear_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/polar_bear_spawn_egg"}},"popped_chorus_fruit":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/popped_chorus_fruit"}},"poppy":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/poppy"}},"porkchop":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/porkchop"}},"potato":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/potato"}},"potion":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/potion_overlay","layer1":"minecraft:item/potion"}},"powder_snow_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/powder_snow_bucket"}},"powered_rail":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/powered_rail"}},"prismarine_crystals":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/prismarine_crystals"}},"prismarine_shard":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/prismarine_shard"}},"prize_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/prize_pottery_sherd"}},"pufferfish":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pufferfish"}},"pufferfish_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pufferfish_bucket"}},"pufferfish_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pufferfish_spawn_egg"}},"pumpkin_pie":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pumpkin_pie"}},"pumpkin_seeds":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pumpkin_seeds"}},"purple_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/purple_wool"}},"purple_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/purple_bundle"}},"purple_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/purple_bundle_open_back"}},"purple_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/purple_bundle_open_front"}},"purple_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/purple_candle"}},"purple_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/purple_dye"}},"purple_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/purple_shulker_box"}},"purple_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/purple_stained_glass"}},"quartz":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/quartz"}},"rabbit":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rabbit"}},"rabbit_foot":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rabbit_foot"}},"rabbit_hide":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rabbit_hide"}},"rabbit_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rabbit_spawn_egg"}},"rabbit_stew":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rabbit_stew"}},"rail":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/rail"}},"raiser_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/raiser_armor_trim_smithing_template"}},"ravager_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ravager_spawn_egg"}},"raw_copper":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/raw_copper"}},"raw_gold":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/raw_gold"}},"raw_iron":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/raw_iron"}},"recovery_compass_00":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_00"}},"recovery_compass_01":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_01"}},"recovery_compass_02":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_02"}},"recovery_compass_03":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_03"}},"recovery_compass_04":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_04"}},"recovery_compass_05":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_05"}},"recovery_compass_06":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_06"}},"recovery_compass_07":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_07"}},"recovery_compass_08":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_08"}},"recovery_compass_09":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_09"}},"recovery_compass_10":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_10"}},"recovery_compass_11":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_11"}},"recovery_compass_12":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_12"}},"recovery_compass_13":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_13"}},"recovery_compass_14":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_14"}},"recovery_compass_15":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_15"}},"recovery_compass_16":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_16"}},"recovery_compass_17":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_17"}},"recovery_compass_18":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_18"}},"recovery_compass_19":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_19"}},"recovery_compass_20":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_20"}},"recovery_compass_21":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_21"}},"recovery_compass_22":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_22"}},"recovery_compass_23":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_23"}},"recovery_compass_24":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_24"}},"recovery_compass_25":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_25"}},"recovery_compass_26":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_26"}},"recovery_compass_27":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_27"}},"recovery_compass_28":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_28"}},"recovery_compass_29":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_29"}},"recovery_compass_30":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_30"}},"recovery_compass_31":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/recovery_compass_31"}},"red_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/red_wool"}},"red_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/red_bundle"}},"red_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/red_bundle_open_back"}},"red_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/red_bundle_open_front"}},"red_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/red_candle"}},"red_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/red_dye"}},"red_mushroom":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/red_mushroom"}},"red_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/red_shulker_box"}},"red_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/red_stained_glass"}},"red_tulip":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/red_tulip"}},"redstone":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/redstone"}},"redstone_torch":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/redstone_torch"}},"repeater":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/repeater"}},"resin_brick":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/resin_brick"}},"resin_clump":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/resin_clump"}},"rib_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rib_armor_trim_smithing_template"}},"rose_bush":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/rose_bush_top"}},"rotten_flesh":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/rotten_flesh"}},"saddle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/saddle"}},"salmon":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/salmon"}},"salmon_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/salmon_bucket"}},"salmon_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/salmon_spawn_egg"}},"scrape_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/scrape_pottery_sherd"}},"sculk_vein":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/sculk_vein"}},"sea_pickle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sea_pickle"}},"seagrass":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/seagrass"}},"sentry_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sentry_armor_trim_smithing_template"}},"shaper_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/shaper_armor_trim_smithing_template"}},"sheaf_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sheaf_pottery_sherd"}},"shears":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/shears"}},"sheep_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sheep_spawn_egg"}},"shelter_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/shelter_pottery_sherd"}},"shield":{"gui_light":"front","textures":{"particle":"block/dark_oak_planks"},"display":{"thirdperson_righthand":{"rotation":[0,90,0],"translation":[10,6,-4],"scale":[1,1,1]},"thirdperson_lefthand":{"rotation":[0,90,0],"translation":[10,6,12],"scale":[1,1,1]},"firstperson_righthand":{"rotation":[0,180,5],"translation":[-10,2,-10],"scale":[1.25,1.25,1.25]},"firstperson_lefthand":{"rotation":[0,180,5],"translation":[10,0,-10],"scale":[1.25,1.25,1.25]},"gui":{"rotation":[15,-25,-5],"translation":[2,3,0],"scale":[0.65,0.65,0.65]},"fixed":{"rotation":[0,180,0],"translation":[-4.5,4.5,-5],"scale":[0.55,0.55,0.55]},"ground":{"rotation":[0,0,0],"translation":[2,4,2],"scale":[0.25,0.25,0.25]}}},"shield_blocking":{"gui_light":"front","textures":{"particle":"block/dark_oak_planks"},"display":{"thirdperson_righthand":{"rotation":[45,155,0],"translation":[-3.49,11,-2],"scale":[1,1,1]},"thirdperson_lefthand":{"rotation":[45,155,0],"translation":[11.51,7,2.5],"scale":[1,1,1]},"firstperson_righthand":{"rotation":[0,180,-5],"translation":[-15,5,-11],"scale":[1.25,1.25,1.25]},"firstperson_lefthand":{"rotation":[0,180,-5],"translation":[5,5,-11],"scale":[1.25,1.25,1.25]},"gui":{"rotation":[15,-25,-5],"translation":[2,3,0],"scale":[0.65,0.65,0.65]}}},"short_dry_grass":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/short_dry_grass"}},"short_grass":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/short_grass"}},"shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/shulker_box"}},"shulker_shell":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/shulker_shell"}},"shulker_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/shulker_spawn_egg"}},"silence_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/silence_armor_trim_smithing_template"}},"silverfish_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/silverfish_spawn_egg"}},"skeleton_horse_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/skeleton_horse_spawn_egg"}},"skeleton_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/skeleton_spawn_egg"}},"skull_banner_pattern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/skull_banner_pattern"}},"skull_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/skull_pottery_sherd"}},"slime_ball":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/slime_ball"}},"slime_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/slime_spawn_egg"}},"small_amethyst_bud":{"parent":"item/amethyst_bud","textures":{"layer0":"minecraft:block/small_amethyst_bud"},"display":{"firstperson_righthand":{"rotation":[0,-90,25],"translation":[0,6,0],"scale":[0.68,0.68,0.68]},"fixed":{"translation":[0,7,0]}}},"small_dripleaf":{"parent":"minecraft:block/small_dripleaf_top","display":{"thirdperson_righthand":{"rotation":[0,0,0],"translation":[0,4,1],"scale":[0.55,0.55,0.55]},"firstperson_righthand":{"rotation":[0,45,0],"translation":[0,3.2,0],"scale":[0.40,0.40,0.40]}}},"sniffer_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sniffer_egg"}},"sniffer_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sniffer_spawn_egg"}},"snort_pottery_sherd":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/snort_pottery_sherd"}},"snout_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/snout_armor_trim_smithing_template"}},"snow_golem_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/snow_golem_spawn_egg"}},"snowball":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/snowball"}},"soul_campfire":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/soul_campfire"}},"soul_lantern":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/soul_lantern"}},"soul_torch":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/soul_torch"}},"spectral_arrow":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spectral_arrow"}},"spider_eye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spider_eye"}},"spider_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spider_spawn_egg"}},"spire_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spire_armor_trim_smithing_template"}},"splash_potion":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/potion_overlay","layer1":"minecraft:item/splash_potion"}},"spruce_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spruce_boat"}},"spruce_chest_boat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spruce_chest_boat"}},"spruce_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spruce_door"}},"spruce_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spruce_hanging_sign"}},"spruce_sapling":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/spruce_sapling"}},"spruce_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spruce_sign"}},"spyglass":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/spyglass"}},"spyglass_in_hand":{"textures":{"spyglass":"item/spyglass_model","particle":"#spyglass"},"elements":[{"from":[7,8.5,7],"to":[9,13.5,9],"faces":{"north":{"uv":[0,2,2,7],"texture":"#spyglass"},"east":{"uv":[0,2,2,7],"texture":"#spyglass"},"south":{"uv":[0,2,2,7],"texture":"#spyglass"},"west":{"uv":[0,2,2,7],"texture":"#spyglass"},"up":{"uv":[0,0,2,2],"texture":"#spyglass"}}},{"from":[6.9,2.4,6.9],"to":[9.1,8.6,9.1],"faces":{"north":{"uv":[0,7,2,13],"texture":"#spyglass"},"east":{"uv":[0,7,2,13],"texture":"#spyglass"},"south":{"uv":[0,7,2,13],"texture":"#spyglass"},"west":{"uv":[0,7,2,13],"texture":"#spyglass"},"up":{"uv":[0,5,2,7],"texture":"#spyglass"},"down":{"uv":[0,13,2,15],"texture":"#spyglass"}}}],"gui_light":"front","display":{"thirdperson_righthand":{"translation":[0,-2,0]},"ground":{"rotation":[90,0,0]},"gui":{"rotation":[-67.5,0,45],"scale":[1.5,1.5,1.5]},"head":{"rotation":[90,0,0],"translation":[0,0,-16],"scale":[1.6,1.6,1.6]},"fixed":{"translation":[0,0,-1.5],"scale":[1.5,1.5,1.5]}}},"squid_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/squid_spawn_egg"}},"stick":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stick"}},"stone_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stone_axe"}},"stone_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stone_hoe"}},"stone_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stone_pickaxe"}},"stone_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stone_shovel"}},"stone_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/stone_sword"}},"stray_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/stray_spawn_egg"}},"strider_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/strider_spawn_egg"}},"string":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/string"}},"structure_void":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/structure_void"}},"sugar":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sugar"}},"sugar_cane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sugar_cane"}},"sunflower":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/sunflower_front"}},"suspicious_stew":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/suspicious_stew"}},"sweet_berries":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/sweet_berries"}},"tadpole_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tadpole_bucket"}},"tadpole_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tadpole_spawn_egg"}},"tall_dry_grass":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/tall_dry_grass"}},"tall_grass":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/tall_grass_top"}},"template_banner":{"gui_light":"front","textures":{"particle":"block/oak_planks"},"display":{"thirdperson_righthand":{"rotation":[0,90,0],"translation":[0,2,0.5],"scale":[0.375,0.375,0.375]},"firstperson_righthand":{"rotation":[0,90,0],"translation":[0,0,0],"scale":[0.375,0.375,0.375]},"gui":{"rotation":[30,20,0],"translation":[0,-3.25,0],"scale":[0.5325,0.5325,0.5325]},"ground":{"rotation":[0,0,0],"translation":[0,1,0],"scale":[0.25,0.25,0.25]},"head":{"rotation":[0,180,0],"translation":[0,16,7],"scale":[1.5,1.5,1.5]},"fixed":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[0.5,0.5,0.5]}}},"template_bed":{"display":{"thirdperson_righthand":{"rotation":[30,160,0],"translation":[0,3,-2],"scale":[0.23,0.23,0.23]},"firstperson_righthand":{"rotation":[30,160,0],"translation":[0,3,0],"scale":[0.375,0.375,0.375]},"gui":{"rotation":[30,160,0],"translation":[2,3,0],"scale":[0.5325,0.5325,0.5325]},"ground":{"rotation":[0,0,0],"translation":[0,1,2],"scale":[0.25,0.25,0.25]},"head":{"rotation":[0,180,0],"translation":[0,10,-8],"scale":[1,1,1]},"fixed":{"rotation":[270,0,0],"translation":[0,4,-2],"scale":[0.5,0.5,0.5]}}},"template_bundle_open_back":{"parent":"minecraft:item/generated","display":{"gui":{"translation":[0,0,-16]}}},"template_bundle_open_front":{"parent":"minecraft:item/generated","display":{"gui":{"translation":[0,0,16]}}},"template_chest":{"display":{"gui":{"rotation":[30,45,0],"translation":[0,0,0],"scale":[0.625,0.625,0.625]},"ground":{"rotation":[0,0,0],"translation":[0,3,0],"scale":[0.25,0.25,0.25]},"head":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[1,1,1]},"fixed":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[0.5,0.5,0.5]},"thirdperson_righthand":{"rotation":[75,315,0],"translation":[0,2.5,0],"scale":[0.375,0.375,0.375]},"firstperson_righthand":{"rotation":[0,315,0],"translation":[0,0,0],"scale":[0.4,0.4,0.4]}}},"template_music_disc":{"parent":"item/generated","gui_light":"front","display":{"fixed":{"rotation":[0,180,0],"translation":[-0.5,0,0]}}},"template_shulker_box":{"display":{"gui":{"rotation":[30,45,0],"translation":[0,0,0],"scale":[0.625,0.625,0.625]},"ground":{"rotation":[0,0,0],"translation":[0,3,0],"scale":[0.25,0.25,0.25]},"head":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[1,1,1]},"fixed":{"rotation":[0,180,0],"translation":[0,0,0],"scale":[0.5,0.5,0.5]},"thirdperson_righthand":{"rotation":[75,315,0],"translation":[0,2.5,0],"scale":[0.375,0.375,0.375]},"firstperson_righthand":{"rotation":[0,315,0],"translation":[0,0,0],"scale":[0.4,0.4,0.4]}}},"template_skull":{"textures":{"particle":"block/soul_sand"},"display":{"gui":{"rotation":[30,45,0],"translation":[0,3,0],"scale":[1,1,1]},"fixed":{"rotation":[0,180,0],"translation":[0,4,0],"scale":[1,1,1]},"ground":{"rotation":[0,0,0],"translation":[0,3,0],"scale":[0.5,0.5,0.5]},"thirdperson_righthand":{"rotation":[45,45,0],"translation":[0,3,0],"scale":[0.5,0.5,0.5]}}},"tide_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tide_armor_trim_smithing_template"}},"tipped_arrow":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tipped_arrow_head","layer1":"minecraft:item/tipped_arrow_base"}},"tnt_minecart":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tnt_minecart"}},"tooting_goat_horn":{"parent":"item/generated","textures":{"layer0":"item/goat_horn"},"display":{"thirdperson_righthand":{"rotation":[0,-125,0],"translation":[-1,2,2],"scale":[0.5,0.5,0.5]},"thirdperson_lefthand":{"rotation":[0,55,0],"translation":[-1,2,2],"scale":[0.5,0.5,0.5]},"firstperson_righthand":{"rotation":[0,-55,-5],"translation":[-1,-2.5,-7.5]},"firstperson_lefthand":{"rotation":[0,115,5],"translation":[0,-2.5,-7.5]}}},"torch":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/torch"}},"torchflower":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/torchflower"}},"torchflower_seeds":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/torchflower_seeds"}},"totem_of_undying":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/totem_of_undying"}},"trader_llama_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/trader_llama_spawn_egg"}},"trapped_chest":{"parent":"minecraft:item/template_chest","textures":{"particle":"minecraft:block/oak_planks"}},"trial_key":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/trial_key"}},"trident":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/trident"}},"trident_in_hand":{"gui_light":"front","textures":{"particle":"item/trident"},"display":{"thirdperson_righthand":{"rotation":[0,60,0],"translation":[11,17,-2],"scale":[1,1,1]},"thirdperson_lefthand":{"rotation":[0,60,0],"translation":[3,17,12],"scale":[1,1,1]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[-3,17,1],"scale":[1,1,1]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[13,17,1],"scale":[1,1,1]},"gui":{"rotation":[15,-25,-5],"translation":[2,3,0],"scale":[0.65,0.65,0.65]},"fixed":{"rotation":[0,180,0],"translation":[-2,4,-5],"scale":[0.5,0.5,0.5]},"ground":{"rotation":[0,0,0],"translation":[4,4,2],"scale":[0.25,0.25,0.25]}}},"trident_throwing":{"gui_light":"front","textures":{"particle":"item/trident"},"display":{"thirdperson_righthand":{"rotation":[0,90,180],"translation":[8,-17,9],"scale":[1,1,1]},"thirdperson_lefthand":{"rotation":[0,90,180],"translation":[8,-17,-7],"scale":[1,1,1]},"firstperson_righthand":{"rotation":[0,-90,25],"translation":[-3,17,1],"scale":[1,1,1]},"firstperson_lefthand":{"rotation":[0,90,-25],"translation":[13,17,1],"scale":[1,1,1]},"gui":{"rotation":[15,-25,-5],"translation":[2,3,0],"scale":[0.65,0.65,0.65]},"fixed":{"rotation":[0,180,0],"translation":[-2,4,-5],"scale":[0.5,0.5,0.5]},"ground":{"rotation":[0,0,0],"translation":[4,4,2],"scale":[0.25,0.25,0.25]}}},"tripwire_hook":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/tripwire_hook"}},"tropical_fish":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tropical_fish"}},"tropical_fish_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tropical_fish_bucket"}},"tropical_fish_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/tropical_fish_spawn_egg"}},"tube_coral":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/tube_coral"}},"tube_coral_fan":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/tube_coral_fan"}},"turtle_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_egg"}},"turtle_helmet":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet"}},"turtle_helmet_amethyst_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_amethyst"}},"turtle_helmet_copper_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_copper"}},"turtle_helmet_diamond_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_diamond"}},"turtle_helmet_emerald_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_emerald"}},"turtle_helmet_gold_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_gold"}},"turtle_helmet_iron_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_iron"}},"turtle_helmet_lapis_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_lapis"}},"turtle_helmet_netherite_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_netherite"}},"turtle_helmet_quartz_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_quartz"}},"turtle_helmet_redstone_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_redstone"}},"turtle_helmet_resin_trim":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_helmet","layer1":"minecraft:trims/items/helmet_trim_resin"}},"turtle_scute":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_scute"}},"turtle_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/turtle_spawn_egg"}},"twisting_vines":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/twisting_vines_plant"}},"vex_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/vex_armor_trim_smithing_template"}},"vex_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/vex_spawn_egg"}},"villager_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/villager_spawn_egg"}},"vindicator_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/vindicator_spawn_egg"}},"vine":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/vine"}},"wandering_trader_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wandering_trader_spawn_egg"}},"ward_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/ward_armor_trim_smithing_template"}},"warden_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/warden_spawn_egg"}},"warped_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/warped_door"}},"warped_fungus":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/warped_fungus"}},"warped_fungus_on_a_stick":{"parent":"minecraft:item/handheld_rod","textures":{"layer0":"minecraft:item/warped_fungus_on_a_stick"}},"warped_hanging_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/warped_hanging_sign"}},"warped_roots":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/warped_roots"}},"warped_sign":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/warped_sign"}},"water_bucket":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/water_bucket"}},"wayfinder_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wayfinder_armor_trim_smithing_template"}},"weathered_copper_door":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/weathered_copper_door"}},"weeping_vines":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/weeping_vines_plant"}},"wheat":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wheat"}},"wheat_seeds":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wheat_seeds"}},"white_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/white_wool"}},"white_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/white_bundle"}},"white_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/white_bundle_open_back"}},"white_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/white_bundle_open_front"}},"white_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/white_candle"}},"white_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/white_dye"}},"white_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/white_shulker_box"}},"white_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/white_stained_glass"}},"white_tulip":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/white_tulip"}},"wild_armor_trim_smithing_template":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wild_armor_trim_smithing_template"}},"wildflowers":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wildflowers"}},"wind_charge":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wind_charge"}},"witch_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/witch_spawn_egg"}},"wither_rose":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/wither_rose"}},"wither_skeleton_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wither_skeleton_spawn_egg"}},"wither_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wither_spawn_egg"}},"wolf_armor":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wolf_armor"}},"wolf_armor_dyed":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wolf_armor","layer1":"minecraft:item/wolf_armor_overlay"}},"wolf_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/wolf_spawn_egg"}},"wooden_axe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/wooden_axe"}},"wooden_hoe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/wooden_hoe"}},"wooden_pickaxe":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/wooden_pickaxe"}},"wooden_shovel":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/wooden_shovel"}},"wooden_sword":{"parent":"minecraft:item/handheld","textures":{"layer0":"minecraft:item/wooden_sword"}},"writable_book":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/writable_book"}},"written_book":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/written_book"}},"yellow_bed":{"parent":"minecraft:item/template_bed","textures":{"particle":"minecraft:block/yellow_wool"}},"yellow_bundle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/yellow_bundle"}},"yellow_bundle_open_back":{"parent":"minecraft:item/template_bundle_open_back","textures":{"layer0":"minecraft:item/yellow_bundle_open_back"}},"yellow_bundle_open_front":{"parent":"minecraft:item/template_bundle_open_front","textures":{"layer0":"minecraft:item/yellow_bundle_open_front"}},"yellow_candle":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/yellow_candle"}},"yellow_dye":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/yellow_dye"}},"yellow_shulker_box":{"parent":"minecraft:item/template_shulker_box","textures":{"particle":"minecraft:block/yellow_shulker_box"}},"yellow_stained_glass_pane":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:block/yellow_stained_glass"}},"zoglin_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/zoglin_spawn_egg"}},"zombie_horse_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/zombie_horse_spawn_egg"}},"zombie_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/zombie_spawn_egg"}},"zombie_villager_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/zombie_villager_spawn_egg"}},"zombified_piglin_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/zombified_piglin_spawn_egg"}}} \ No newline at end of file diff --git a/common-files/src/main/resources/mappings.yml b/common-files/src/main/resources/mappings.yml index 94fa679ec..14078dd87 100644 --- a/common-files/src/main/resources/mappings.yml +++ b/common-files/src/main/resources/mappings.yml @@ -12,7 +12,7 @@ minecraft:jungle_sapling[stage=1]: minecraft:jungle_sapling[stage=0] minecraft:dark_oak_sapling[stage=1]: minecraft:dark_oak_sapling[stage=0] minecraft:acacia_sapling[stage=1]: minecraft:acacia_sapling[stage=0] minecraft:cherry_sapling[stage=1]: minecraft:cherry_sapling[stage=0] -#minecraft:pale_oak_leaves[stage=1]: minecraft:pale_oak_leaves[stage=0] # 1.21.4+ +#minecraft:pale_oak_sapling[stage=1]: minecraft:pale_oak_sapling[stage=0] # 1.21.4+ ######################################################################################################################################################################################################################## # Ideal block for lower half slabs # Sculk Sensor diff --git a/common-files/src/main/resources/resources/default/configuration/blocks.yml b/common-files/src/main/resources/resources/default/configuration/blocks.yml index 4c1fbbc7d..3fa3526c9 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks.yml @@ -167,7 +167,7 @@ items#misc: template: "default:loot_table/self" settings: template: - - default:sound/sand + - default:sound/stone - default:pickaxe_power/level_1 - default:settings/solid_1x1x1 overrides: diff --git a/common-files/src/main/resources/resources/default/configuration/emoji.yml b/common-files/src/main/resources/resources/default/configuration/emoji.yml index 996057731..95dda77c6 100644 --- a/common-files/src/main/resources/resources/default/configuration/emoji.yml +++ b/common-files/src/main/resources/resources/default/configuration/emoji.yml @@ -2,7 +2,7 @@ templates: default:emoji/basic: content: "'>" default:emoji/addition_info: - content: "'>{text}" + content: "'>${text}" emoji: default:emoji_location: diff --git a/common-files/src/main/resources/resources/default/configuration/fix_client_visual.yml b/common-files/src/main/resources/resources/default/configuration/fix_client_visual.yml index 9e18aabaf..d4167b5c0 100644 --- a/common-files/src/main/resources/resources/default/configuration/fix_client_visual.yml +++ b/common-files/src/main/resources/resources/default/configuration/fix_client_visual.yml @@ -1,5 +1,4 @@ items: - # client-bound-data requires CraftEngine mod to apply minecraft:string: client-bound-data: components: diff --git a/common-files/src/main/resources/resources/default/configuration/items.yml b/common-files/src/main/resources/resources/default/configuration/items.yml index eb329e847..5d2b4ba4c 100644 --- a/common-files/src/main/resources/resources/default/configuration/items.yml +++ b/common-files/src/main/resources/resources/default/configuration/items.yml @@ -229,16 +229,16 @@ items#topaz_gears: templates: default:armor/topaz: - material: "chainmail_{part}" + material: "chainmail_${part}" custom-model-data: 1000 data: - item-name: "<#FF8C00>" + item-name: "<#FF8C00>" tooltip-style: minecraft:topaz settings: tags: - "default:topaz_tools" equippable: - slot: "{slot}" + slot: "${slot}" asset-id: topaz humanoid: "minecraft:topaz" humanoid-leggings: "minecraft:topaz" @@ -247,111 +247,111 @@ templates: property: minecraft:trim_material fallback: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}" + path: "minecraft:item/custom/topaz_${part}" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" + "layer0": "minecraft:item/custom/topaz_${part}" cases: - when: minecraft:quartz model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_quartz_trim" + path: "minecraft:item/custom/topaz_${part}_quartz_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_quartz" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_quartz" - when: minecraft:iron model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_iron_trim" + path: "minecraft:item/custom/topaz_${part}_iron_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_iron" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_iron" - when: minecraft:netherite model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_netherite_trim" + path: "minecraft:item/custom/topaz_${part}_netherite_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_netherite" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_netherite" - when: minecraft:redstone model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_redstone_trim" + path: "minecraft:item/custom/topaz_${part}_redstone_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_redstone" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_redstone" - when: minecraft:copper model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_copper_trim" + path: "minecraft:item/custom/topaz_${part}_copper_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_copper" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_copper" - when: minecraft:gold model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_gold_trim" + path: "minecraft:item/custom/topaz_${part}_gold_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_gold" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_gold" - when: minecraft:emerald model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_emerald_trim" + path: "minecraft:item/custom/topaz_${part}_emerald_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_emerald" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_emerald" - when: minecraft:diamond model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_diamond_trim" + path: "minecraft:item/custom/topaz_${part}_diamond_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_diamond" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_diamond" - when: minecraft:lapis model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_lapis_trim" + path: "minecraft:item/custom/topaz_${part}_lapis_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_lapis" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_lapis" - when: minecraft:amethyst model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_amethyst_trim" + path: "minecraft:item/custom/topaz_${part}_amethyst_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_amethyst" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_amethyst" - when: minecraft:resin model: type: minecraft:model - path: "minecraft:item/custom/topaz_{part}_resin_trim" + path: "minecraft:item/custom/topaz_${part}_resin_trim" generation: parent: "minecraft:item/generated" textures: - "layer0": "minecraft:item/custom/topaz_{part}" - "layer1": "minecraft:trims/items/{part}_trim_resin" + "layer0": "minecraft:item/custom/topaz_${part}" + "layer1": "minecraft:trims/items/${part}_trim_resin" recipes#11: default:topaz_shovel: diff --git a/common-files/src/main/resources/resources/default/configuration/templates.yml b/common-files/src/main/resources/resources/default/configuration/templates.yml index d6e8db003..73324b0ed 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -7,32 +7,32 @@ templates#models#block: # model: model_path # texture: texture_path default:model/cube_all: - path: "{model}" + path: "${model}" generation: parent: "minecraft:block/cube_all" textures: - "all": "{texture}" + "all": "${texture}" # template: default:model/simplified_cube_all # arguments: # path: [model/texture]_path default:model/simplified_cube_all: - path: "{path}" + path: "${path}" generation: parent: "minecraft:block/cube_all" textures: - "all": "{path}" + "all": "${path}" # template: default:model/cube_column # arguments: # model: model_path # end_texture: end_texture_path # side_texture: side_texture_path default:model/cube_column: - path: "{model}" + path: "${model}" generation: parent: "minecraft:block/cube_column" textures: - "end": "{end_texture}" - "side": "{side_texture}" + "end": "${end_texture}" + "side": "${side_texture}" # template: default:model/cube # arguments: # model: model_path @@ -44,7 +44,7 @@ templates#models#block: # south_texture: south_texture_path # west_texture: west_texture_path default:model/cube: - path: "{model}" + path: "${model}" generation: parent: "minecraft:block/cube_column" textures: @@ -64,21 +64,21 @@ templates#models#2d: # texture: texture_path default:model/generated: type: "minecraft:model" - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{texture}" + "layer0": "${texture}" # template: default:model/simplified_generated # arguments: # path: [model/texture]_path default:model/simplified_generated: type: "minecraft:model" - path: "{path}" + path: "${path}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{path}" + "layer0": "${path}" # template: default:model/2_layer_generated # arguments: # model: model_path @@ -86,33 +86,33 @@ templates#models#2d: # layer1: texture_path default:model/2_layer_generated: type: "minecraft:model" - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{layer0}" - "layer1": "{layer1}" + "layer0": "${layer0}" + "layer1": "${layer1}" # template: default:model/handheld # arguments: # model: model_path # texture: texture_path default:model/handheld: type: "minecraft:model" - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/handheld" textures: - "layer0": "{texture}" + "layer0": "${texture}" # template: default:model/simplified_handheld # arguments: # path: [model/texture]_path default:model/simplified_handheld: type: "minecraft:model" - path: "{path}" + path: "${path}" generation: parent: "minecraft:item/handheld" textures: - "layer0": "{path}" + "layer0": "${path}" # template: default:model/elytra # arguments: # model: model_path @@ -123,17 +123,17 @@ templates#models#2d: type: "minecraft:condition" property: minecraft:broken on-false: - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{texture}" + "layer0": "${texture}" on-true: - path: "{broken_model}" + path: "${broken_model}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{broken_texture}" + "layer0": "${broken_texture}" # template: default:model/simplified_elytra # arguments: # path: [model/texture]_path @@ -141,10 +141,10 @@ templates#models#2d: default:model/simplified_elytra: template: default:model/elytra arguments: - model: "{path}" - texture: "{path}" - broken_model: "{broken_path}" - broken_texture: "{broken_path}" + model: "${path}" + texture: "${path}" + broken_model: "${broken_path}" + broken_texture: "${broken_path}" # shield templates#models#shield: @@ -157,10 +157,10 @@ templates#models#shield: property: "minecraft:using_item" on-false: type: minecraft:model - path: "{model}" + path: "${model}" on-true: type: minecraft:model - path: "{block_model}" + path: "${block_model}" # fishing rods templates#models#fishing_rod: @@ -173,10 +173,10 @@ templates#models#fishing_rod: property: "minecraft:fishing_rod/cast" on-false: type: "minecraft:model" - path: "{model}" + path: "${model}" on-true: type: "minecraft:model" - path: "{cast_model}" + path: "${cast_model}" # template: default:model/fishing_rod_2d # arguments: # model: rod_model_path @@ -188,18 +188,18 @@ templates#models#fishing_rod: property: "minecraft:fishing_rod/cast" on-false: type: "minecraft:model" - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/fishing_rod" textures: - "layer0": "{texture}" + "layer0": "${texture}" on-true: type: "minecraft:model" - path: "{cast_model}" + path: "${cast_model}" generation: parent: "minecraft:item/fishing_rod" textures: - "layer0": "{cast_texture}" + "layer0": "${cast_texture}" # template: default:model/simplified_fishing_rod_2d # arguments: # path: rod_[model/texture]_path @@ -207,10 +207,10 @@ templates#models#fishing_rod: default:model/simplified_fishing_rod_2d: template: default:model/fishing_rod_2d arguments: - texture: "{path}" - model: "{path}" - cast_texture: "{cast_path}" - cast_model: "{cast_path}" + texture: "${path}" + model: "${path}" + cast_texture: "${cast_path}" + cast_model: "${cast_path}" # bows templates#models#bow: @@ -225,7 +225,7 @@ templates#models#bow: property: "minecraft:using_item" on-false: type: "minecraft:model" - path: "{model}" + path: "${model}" on-true: type: "minecraft:range_dispatch" property: "minecraft:use_duration" @@ -233,15 +233,15 @@ templates#models#bow: entries: - model: type: minecraft:model - path: "{pulling_1_model}" + path: "${pulling_1_model}" threshold: 0.65 - model: type: minecraft:model - path: "{pulling_2_model}" + path: "${pulling_2_model}" threshold: 0.9 fallback: type: minecraft:model - path: "{pulling_0_model}" + path: "${pulling_0_model}" # template: default:model/bow_2d # arguments: # model: bow_model_path @@ -257,11 +257,11 @@ templates#models#bow: property: "minecraft:using_item" on-false: type: "minecraft:model" - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/bow" textures: - "layer0": "{texture}" + "layer0": "${texture}" on-true: type: "minecraft:range_dispatch" property: "minecraft:use_duration" @@ -269,27 +269,27 @@ templates#models#bow: entries: - model: type: minecraft:model - path: "{pulling_1_model}" + path: "${pulling_1_model}" generation: parent: "minecraft:item/bow_pulling_1" textures: - "layer0": "{pulling_1_texture}" + "layer0": "${pulling_1_texture}" threshold: 0.65 - model: type: minecraft:model - path: "{pulling_2_model}" + path: "${pulling_2_model}" generation: parent: "minecraft:item/bow_pulling_2" textures: - "layer0": "{pulling_2_texture}" + "layer0": "${pulling_2_texture}" threshold: 0.9 fallback: type: minecraft:model - path: "{pulling_0_model}" + path: "${pulling_0_model}" generation: parent: "minecraft:item/bow_pulling_0" textures: - "layer0": "{pulling_0_texture}" + "layer0": "${pulling_0_texture}" # template: default:model/simplified_bow_2d # arguments: # path: bow_[model/texture]_path @@ -299,14 +299,14 @@ templates#models#bow: default:model/simplified_bow_2d: template: default:model/bow_2d arguments: - model: "{path}" - pulling_0_model: "{pulling_0_path}" - pulling_1_model: "{pulling_1_path}" - pulling_2_model: "{pulling_2_path}" - texture: "{path}" - pulling_0_texture: "{pulling_0_path}" - pulling_1_texture: "{pulling_1_path}" - pulling_2_texture: "{pulling_2_path}" + model: "${path}" + pulling_0_model: "${pulling_0_path}" + pulling_1_model: "${pulling_1_path}" + pulling_2_model: "${pulling_2_path}" + texture: "${path}" + pulling_0_texture: "${pulling_0_path}" + pulling_1_texture: "${pulling_1_path}" + pulling_2_texture: "${pulling_2_path}" # crossbows templates#models#crossbow: @@ -328,29 +328,29 @@ templates#models#crossbow: - when: arrow model: type: minecraft:model - path: "{arrow_model}" + path: "${arrow_model}" - when: rocket model: type: minecraft:model - path: "{firework_model}" + path: "${firework_model}" fallback: type: minecraft:model - path: "{model}" + path: "${model}" on-true: type: "minecraft:range_dispatch" property: "minecraft:crossbow/pull" entries: - model: type: minecraft:model - path: "{pulling_1_model}" + path: "${pulling_1_model}" threshold: 0.58 - model: type: minecraft:model - path: "{pulling_2_model}" + path: "${pulling_2_model}" threshold: 1.0 fallback: type: minecraft:model - path: "{pulling_0_model}" + path: "${pulling_0_model}" # template: default:model/crossbow_2d # arguments: # model: crossbow_model_path @@ -375,53 +375,53 @@ templates#models#crossbow: - when: arrow model: type: minecraft:model - path: "{arrow_model}" + path: "${arrow_model}" generation: parent: "minecraft:item/crossbow_arrow" textures: - "layer0": "{arrow_texture}" + "layer0": "${arrow_texture}" - when: rocket model: type: minecraft:model - path: "{firework_model}" + path: "${firework_model}" generation: parent: "minecraft:item/crossbow_firework" textures: - "layer0": "{firework_texture}" + "layer0": "${firework_texture}" fallback: type: minecraft:model - path: "{model}" + path: "${model}" generation: parent: "minecraft:item/crossbow" textures: - "layer0": "{texture}" + "layer0": "${texture}" on-true: type: "minecraft:range_dispatch" property: "minecraft:crossbow/pull" entries: - model: type: minecraft:model - path: "{pulling_1_model}" + path: "${pulling_1_model}" generation: parent: "minecraft:item/crossbow_pulling_1" textures: - "layer0": "{pulling_1_texture}" + "layer0": "${pulling_1_texture}" threshold: 0.58 - model: type: minecraft:model - path: "{pulling_2_model}" + path: "${pulling_2_model}" generation: parent: "minecraft:item/crossbow_pulling_2" textures: - "layer0": "{pulling_2_texture}" + "layer0": "${pulling_2_texture}" threshold: 1.0 fallback: type: minecraft:model - path: "{pulling_0_model}" + path: "${pulling_0_model}" generation: parent: "minecraft:item/crossbow_pulling_0" textures: - "layer0": "{pulling_0_texture}" + "layer0": "${pulling_0_texture}" # template: default:model/simplified_crossbow_2d # arguments: # path: crossbow_[model/texture]_path @@ -433,28 +433,28 @@ templates#models#crossbow: default:model/simplified_crossbow_2d: template: default:model/crossbow_2d arguments: - model: "{path}" - texture: "{path}" - arrow_model: "{arrow_path}" - arrow_texture: "{arrow_path}" - firework_model: "{firework_path}" - firework_texture: "{firework_path}" - pulling_0_model: "{pulling_0_path}" - pulling_0_texture: "{pulling_0_path}" - pulling_1_model: "{pulling_1_path}" - pulling_1_texture: "{pulling_1_path}" - pulling_2_model: "{pulling_2_path}" - pulling_2_texture: "{pulling_2_path}" + model: "${path}" + texture: "${path}" + arrow_model: "${arrow_path}" + arrow_texture: "${arrow_path}" + firework_model: "${firework_path}" + firework_texture: "${firework_path}" + pulling_0_model: "${pulling_0_path}" + pulling_0_texture: "${pulling_0_path}" + pulling_1_model: "${pulling_1_path}" + pulling_1_texture: "${pulling_1_path}" + pulling_2_model: "${pulling_2_path}" + pulling_2_texture: "${pulling_2_path}" # sounds templates#settings#sounds: default:sound/block_template: sounds: - break: "minecraft:block.{block_type}.break" - step: "minecraft:block.{block_type}.step" - place: "minecraft:block.{block_type}.place" - hit: "minecraft:block.{block_type}.hit" - fall: "minecraft:block.{block_type}.fall" + break: "minecraft:block.${block_type}.break" + step: "minecraft:block.${block_type}.step" + place: "minecraft:block.${block_type}.place" + hit: "minecraft:block.${block_type}.hit" + fall: "minecraft:block.${block_type}.fall" default:sound/crop: sounds: break: "minecraft:block.crop.break" @@ -614,7 +614,7 @@ templates#settings#break_level: # block settings templates#settings#blocks: default:settings/middle_click_pick_itself: - item: "{__NAMESPACE__}:{__ID__}" + item: "${__NAMESPACE__}:${__ID__}" default:settings/solid_1x1x1: is-suffocating: true replaceable: false @@ -696,7 +696,7 @@ templates#settings#blocks: default:settings/ore: template: - "default:sound/stone" - - "default:pickaxe_power/level_{break_power}" + - "default:pickaxe_power/level_${break_power}" overrides: hardness: 3.0 resistance: 3.0 @@ -712,7 +712,7 @@ templates#settings#blocks: default:settings/deepslate_ore: template: - "default:sound/deepslate" - - "default:pickaxe_power/level_{break_power}" + - "default:pickaxe_power/level_${break_power}" overrides: hardness: 4.5 resistance: 3.0 @@ -735,45 +735,45 @@ templates#block_states: default: y appearances: axisY: - state: "{base_block}:{vanilla_id}" + state: "${base_block}:${vanilla_id}" model: - path: "{model_vertical_path}" + path: "${model_vertical_path}" generation: parent: "minecraft:block/cube_column" textures: - "end": "{texture_top_path}" - "side": "{texture_side_path}" + "end": "${texture_top_path}" + "side": "${texture_side_path}" axisX: - state: "{base_block}:{vanilla_id}" + state: "${base_block}:${vanilla_id}" model: x: 90 y: 90 - path: "{model_horizontal_path}" + path: "${model_horizontal_path}" generation: parent: "minecraft:block/cube_column_horizontal" textures: - "end": "{texture_top_path}" - "side": "{texture_side_path}" + "end": "${texture_top_path}" + "side": "${texture_side_path}" axisZ: - state: "{base_block}:{vanilla_id}" + state: "${base_block}:${vanilla_id}" model: x: 90 - path: "{model_horizontal_path}" + path: "${model_horizontal_path}" generation: parent: "minecraft:block/cube_column_horizontal" textures: - "end": "{texture_top_path}" - "side": "{texture_side_path}" + "end": "${texture_top_path}" + "side": "${texture_side_path}" variants: axis=x: appearance: axisX - id: "{internal_id}" + id: "${internal_id}" axis=y: appearance: axisY - id: "{internal_id}" + id: "${internal_id}" axis=z: appearance: axisZ - id: "{internal_id}" + id: "${internal_id}" default:block_state/leaves: properties: waterlogged: @@ -788,107 +788,107 @@ templates#block_states: range: 1~7 appearances: default: - state: "{default_state}" + state: "${default_state}" model: - path: "{model_path}" + path: "${model_path}" generation: parent: "minecraft:block/leaves" textures: - "all": "{texture_path}" + "all": "${texture_path}" waterlogged: - state: "{waterlogged_state}" + state: "${waterlogged_state}" model: - path: "{model_path}" + path: "${model_path}" variants: distance=1,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=2,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=3,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=4,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=5,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=6,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=7,persistent=false,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" settings: is-randomly-ticking: true distance=1,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=2,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=3,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=4,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=5,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=6,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=7,persistent=true,waterlogged=false: appearance: "default" - id: "{internal_id}" + id: "${internal_id}" distance=1,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=2,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=3,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=4,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=5,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=6,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=7,persistent=false,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false @@ -896,49 +896,49 @@ templates#block_states: fluid-state: water distance=1,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=2,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=3,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=4,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=5,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=6,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false fluid-state: water distance=7,persistent=true,waterlogged=true: appearance: "waterlogged" - id: "{internal_id}" + id: "${internal_id}" settings: resistance: 1200.0 burnable: false @@ -951,9 +951,9 @@ templates#recipes: category: building group: planks ingredients: - A: "#default:{wood_type}_logs" + A: "#default:${wood_type}_logs" result: - id: "default:{wood_type}_planks" + id: "default:${wood_type}_planks" count: 4 default:recipe/log_2_wood: type: shaped @@ -963,29 +963,29 @@ templates#recipes: - "AA" - "AA" ingredients: - A: "default:{wood_type}_log" + A: "default:${wood_type}_log" result: - id: "default:{wood_type}_wood" + id: "default:${wood_type}_wood" count: 3 default:recipe/smelting_ore: type: smelting - experience: "{exp}" + experience: "${exp}" category: misc group: topaz time: 200 - ingredient: "{ingredient}" + ingredient: "${ingredient}" result: - id: "{result}" + id: "${result}" count: 1 default:recipe/blasting_ore: type: blasting - experience: "{exp}" + experience: "${exp}" category: misc group: topaz time: 100 - ingredient: "{ingredient}" + ingredient: "${ingredient}" result: - id: "{result}" + id: "${result}" count: 1 # loot tables @@ -1001,7 +1001,7 @@ templates#loot_tables: - type: survives_explosion entries: - type: item - item: "{__NAMESPACE__}:{__ID__}" + item: "${__NAMESPACE__}:${__ID__}" # drop one item @@ -1015,7 +1015,7 @@ templates#loot_tables: - type: survives_explosion entries: - type: item - item: "{item}" + item: "${item}" # drop the original furniture item or a fallback item @@ -1027,7 +1027,7 @@ templates#loot_tables: - rolls: 1 entries: - type: furniture_item - item: "{item}" + item: "${item}" # drop with silk touch @@ -1042,7 +1042,7 @@ templates#loot_tables: predicate: minecraft:silk_touch>=1 entries: - type: item - item: "{item}" + item: "${item}" # crop drops @@ -1058,21 +1058,21 @@ templates#loot_tables: - type: alternatives children: - type: item - item: "{crop_item}" + item: "${crop_item}" conditions: - type: match_block_property properties: - age: "{ripe_age}" + age: "${ripe_age}" - type: item - item: "{crop_seed}" + item: "${crop_seed}" - rolls: 1 conditions: - type: match_block_property properties: - age: "{ripe_age}" + age: "${ripe_age}" entries: - type: item - item: "{crop_seed}" + item: "${crop_seed}" functions: - type: apply_bonus enchantment: minecraft:fortune @@ -1090,15 +1090,15 @@ templates#loot_tables: - rolls: 1 entries: - type: item - item: "{crop_item}" + item: "${crop_item}" - rolls: 1 conditions: - type: match_block_property properties: - age: "{ripe_age}" + age: "${ripe_age}" entries: - type: item - item: "{crop_item}" + item: "${crop_item}" functions: - type: apply_bonus enchantment: minecraft:fortune @@ -1122,12 +1122,12 @@ templates#loot_tables: - type: alternatives children: - type: item - item: "{ore_block}" + item: "${ore_block}" conditions: - type: enchantment predicate: minecraft:silk_touch>=1 - type: item - item: "{ore_drop}" + item: "${ore_drop}" functions: - type: apply_bonus enchantment: minecraft:fortune @@ -1137,8 +1137,8 @@ templates#loot_tables: - type: drop_exp count: type: uniform - min: "{min_exp}" - max: "{max_exp}" + min: "${min_exp:-2}" + max: "${max_exp:-4}" # template: default:loot_table/ore_no_exp # arguments: @@ -1151,12 +1151,12 @@ templates#loot_tables: - type: alternatives children: - type: item - item: "{ore_block}" + item: "${ore_block}" conditions: - type: enchantment predicate: minecraft:silk_touch>=1 - type: item - item: "{ore_drop}" + item: "${ore_drop}" functions: - type: apply_bonus enchantment: minecraft:fortune @@ -1177,7 +1177,7 @@ templates#loot_tables: - type: alternatives children: - type: item - item: "{leaves}" + item: "${leaves}" conditions: - type: any_of terms: @@ -1186,7 +1186,7 @@ templates#loot_tables: - type: enchantment predicate: minecraft:silk_touch>=1 - type: item - item: "{sapling}" + item: "${sapling}" conditions: - type: survives_explosion - type: table_bonus diff --git a/common-files/src/main/resources/resources/internal/configuration/gui.yml b/common-files/src/main/resources/resources/internal/configuration/gui.yml index 9c32bd009..f01daf055 100644 --- a/common-files/src/main/resources/resources/internal/configuration/gui.yml +++ b/common-files/src/main/resources/resources/internal/configuration/gui.yml @@ -69,21 +69,21 @@ images: templates: internal:icon/2d: material: arrow - custom-model-data: "{model_data}" + custom-model-data: "${model_data}" data: - item-name: "{name}" - lore: "{lore}" + item-name: "${name}" + lore: "${lore}" model: template: "internal:model/simplified_generated" arguments: - path: "minecraft:item/custom/gui/{texture}" + path: "minecraft:item/custom/gui/${texture}" internal:model/simplified_generated: type: "minecraft:model" - path: "{path}" + path: "${path}" generation: parent: "minecraft:item/generated" textures: - "layer0": "{path}" + "layer0": "${path}" items: internal:next_page_0: diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 31d995f66..63e387783 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -64,6 +64,7 @@ command.upload.on_progress: "Started uploading progress. Check the consol command.send_resource_pack.success.single: "Sent resource pack to ." command.send_resource_pack.success.multiple: "Send resource packs to players." warning.config.pack.duplicated_files: "Duplicated files Found. Please resolve them through config.yml 'resource-pack.duplicated-files-handler' section." +warning.config.yaml.duplicated_key: "Issue found in file - Found duplicated key '' at line , this might cause unexpected results." warning.config.type.int: "Issue found in file - Failed to load '': Cannot cast '' to integer type for option ''." warning.config.type.float: "Issue found in file - Failed to load '': Cannot cast '' to float type for option ''." warning.config.type.double: "Issue found in file - Failed to load '': Cannot cast '' to double type for option ''." @@ -113,7 +114,6 @@ warning.config.image.missing_char: "Issue found in file - The im warning.config.image.codepoint_conflict: "Issue found in file - The image '' is using a character '()' in font that has been used by another image ''." warning.config.image.invalid_codepoint_grid: "Issue found in file - Image '' has an invalid 'chars' codepoint grid." warning.config.image.invalid_char: "Issue found in file - Image '' has a char parameter containing combining characters, which may result in image splitting." -warning.config.image.file_not_found: "Issue found in file - PNG file '' not found for image ''." warning.config.image.invalid_hex_value: "Issue found in file - The image '' is using a unicode character '' that is not a valid hexadecimal (radix 16) value." warning.config.recipe.duplicate: "Issue found in file - Duplicated recipe ''. Please check if there is the same configuration in other files." warning.config.recipe.missing_type: "Issue found in file - The recipe '' is missing the required 'type' argument." @@ -133,8 +133,10 @@ warning.config.recipe.smithing_transform.post_processor.keep_component.missing_c warning.config.recipe.smithing_transform.post_processor.keep_component.missing_tags: "Issue found in file - The smithing transform recipe '' is missing the required argument 'tags' for post-processors 'keep_tags'." warning.config.i18n.unknown_locale: "Issue found in file - Unknown locale ''." warning.config.template.duplicate: "Issue found in file - Duplicated template ''. Please check if there is the same configuration in other files." +warning.config.template.invalid: "Issue found in file - The config '' is using an invalid template ''." warning.config.template.argument.self_increase_int.invalid_range: "Issue found in file - The template '' is using a 'from' '' larger than 'to' '' in 'self_increase_int' argument." warning.config.template.argument.list.invalid_type: "Issue found in file - The template '' is using a 'list' argument which expects a 'List' as argument while the input argument is a(n) ''." +warning.config.template.argument.default_value.invalid_syntax: "Issue found in file - The template '' is using an invalid default value '' for argument ''." warning.config.vanilla_loot.missing_type: "Issue found in file - The vanilla loot '' is missing the required 'type' argument." warning.config.vanilla_loot.invalid_type: "Issue found in file - The vanilla loot '' is using an invalid type ''. Allowed types: []." warning.config.vanilla_loot.block.invalid_target: "Issue found in file - Invalid block target '' in vanilla loot ''." @@ -151,11 +153,13 @@ warning.config.furniture.hitbox.invalid_type: "Issue found in file Issue found in file - The furniture '' is using a custom hitbox with invalid entity type ''." warning.config.item.duplicate: "Issue found in file - Duplicated item ''. Please check if there is the same configuration in other files." warning.config.item.settings.unknown: "Issue found in file - The item '' is using an unknown setting type ''." +warning.config.item.settings.invulnerable.invalid_damage_source: "Issue found in file - The item '' is using an unknown damage source ''. Allowed sources: []." warning.config.item.missing_material: "Issue found in file - The item '' is missing the required 'material' argument." warning.config.item.invalid_material: "Issue found in file - The item '' is using an invalid material type ''." warning.config.item.invalid_custom_model_data: "Issue found in file - The item '' is using a negative custom model data '' which is invalid." warning.config.item.bad_custom_model_data: "Issue found in file - The item '' is using a custom model data '' that is too large. It's recommended to use a value lower than 16,777,216." warning.config.item.custom_model_data_conflict: "Issue found in file - The item '' is using a custom model data '' that has been occupied by item ''." +warning.config.item.invalid_component: "Issue found in file - The item '' is using a non-existing component type ''." warning.config.item.missing_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." warning.config.item.missing_model: "Issue found in file - The item '' is missing the required 'model' section for 1.21.4+ resource pack support." warning.config.item.behavior.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for its item behavior." @@ -349,4 +353,9 @@ warning.config.selector.invalid_type: "Issue found in file - The warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." warning.config.resource_pack.item_model.conflict.vanilla: "Failed to generate item model for '' because this item model has been occupied by a vanilla item." warning.config.resource_pack.item_model.already_exist: "Failed to generate item model for '' because the file '' already exists." -warning.config.resource_pack.model.generation.already_exist: "Failed to generate model because the model file '' already exists." \ No newline at end of file +warning.config.resource_pack.model.generation.already_exist: "Failed to generate model because the model file '' already exists." +warning.config.resource_pack.generation.missing_font_texture: "Font '' is missing required texture: ''" +warning.config.resource_pack.generation.missing_model_texture: "Model '' is missing texture ''" +warning.config.resource_pack.generation.missing_item_model: "Item '' is missing model file: ''" +warning.config.resource_pack.generation.missing_block_model: "Block '' is missing model file: ''" +warning.config.resource_pack.generation.missing_parent_model: "Model '' cannot find parent model: ''" \ No newline at end of file diff --git a/common-files/src/main/resources/translations/tr.yml b/common-files/src/main/resources/translations/tr.yml index 7c1c475b5..64f30f644 100644 --- a/common-files/src/main/resources/translations/tr.yml +++ b/common-files/src/main/resources/translations/tr.yml @@ -79,7 +79,6 @@ warning.config.image.invalid_font_chars: " dosyasında sorun bulu warning.config.image.missing_char: " dosyasında sorun bulundu - '' resmi gerekli 'char' argümanı eksik." warning.config.image.codepoint_conflict: " dosyasında sorun bulundu - '' resmi, yazı tipinde başka bir resim '' tarafından kullanılmış olan '()' karakterini kullanıyor." warning.config.image.invalid_codepoint_grid: " dosyasında sorun bulundu - '' resminin geçersiz bir 'chars' kod noktası ızgarası var." -warning.config.image.file_not_found: " dosyasında sorun bulundu - '' resmi için '' PNG dosyası bulunamadı." warning.config.image.invalid_hex_value: " dosyasında sorun bulundu - '' resmi, geçerli bir onaltılık (16 tabanlı) değer olmayan '' unicode karakterini kullanıyor." warning.config.recipe.duplicate: " dosyasında sorun bulundu - Yinelenen tarif ''. Diğer dosyalarda aynı yapılandırmanın olup olmadığını kontrol edin." warning.config.recipe.missing_type: " dosyasında sorun bulundu - '' tarifi gerekli 'type' argümanı eksik." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index d9feadebf..42e4155d7 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -64,6 +64,7 @@ command.upload.on_progress: "已开始上传进程. 检查控制台以获 command.send_resource_pack.success.single: "发送资源包给 " command.send_resource_pack.success.multiple: "发送资源包给 个玩家" warning.config.pack.duplicated_files: "发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决" +warning.config.yaml.duplicated_key: "在文件 发现问题 - 在第行发现重复的键 '', 这可能会导致一些意料之外的问题." warning.config.type.int: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为整数类型 (选项 '')" warning.config.type.float: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为浮点数类型 (选项 '')" warning.config.type.double: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为双精度类型 (选项 '')" @@ -113,7 +114,6 @@ warning.config.image.missing_char: "在文件 发现问题 - 图 warning.config.image.codepoint_conflict: "在文件 发现问题 - 图片 '' 在字体 中使用的字符 '()' 已被其他图片 '' 占用" warning.config.image.invalid_codepoint_grid: "在文件 发现问题 - 图片 '' 的 'chars' 码位网格无效" warning.config.image.invalid_char: "在文件 发现问题 - 图片 '' 的 'char' 参数包含组合字符可能导致图片分裂" -warning.config.image.file_not_found: "在文件 发现问题 - 图片 '' 的 PNG 文件 '' 未找到" warning.config.image.invalid_hex_value: "在文件 发现问题 - 图片 '' 使用的 Unicode 字符 '' 不是有效的十六进制值" warning.config.recipe.duplicate: "在文件 发现问题 - 重复的配方 '' 请检查其他文件中是否存在相同配置" warning.config.recipe.missing_type: "在文件 发现问题 - 配方 '' 缺少必需的 'type' 参数" @@ -134,7 +134,9 @@ warning.config.recipe.smithing_transform.post_processor.keep_component.missing_t warning.config.i18n.unknown_locale: "在文件 发现问题 - 未知的语言环境 ''" warning.config.template.duplicate: "在文件 发现问题 - 重复的模板 '' 请检查其他文件中是否存在相同配置" warning.config.template.argument.self_increase_int.invalid_range: "在文件 发现问题 - 模板 '' 在 'self_increase_int' 参数中使用了一个起始值 '' 大于终止值 ''" +warning.config.template.invalid: "在文件 发现问题 - 配置 '' 使用了无效的模板 ''." warning.config.template.argument.list.invalid_type: "在文件 发现问题 - 模板 '' 的 'list' 参数需要列表类型 但输入参数类型为 ''" +warning.config.template.argument.default_value.invalid_syntax: "在文件 发现问题 - 模板 '' 在参数 '' 中使用了无效的默认值 ''." warning.config.vanilla_loot.missing_type: "在文件 发现问题 - 原版战利品 '' 缺少必需的 'type' 参数" warning.config.vanilla_loot.invalid_type: "在文件 发现问题 - 原版战利品 '' 使用了无效类型 '' 允许的类型: []" warning.config.vanilla_loot.block.invalid_target: "在文件 发现问题 - 原版战利品 '' 中存在无效的方块目标 ''" @@ -151,11 +153,13 @@ warning.config.furniture.hitbox.invalid_type: "在文件 发现 warning.config.furniture.hitbox.custom.invalid_entity: "在文件 发现问题 - 家具 '' 的自定义碰撞箱使用了无效的实体类型 ''" warning.config.item.duplicate: "在文件 发现问题 - 重复的物品 '' 请检查其他文件中是否存在相同配置" warning.config.item.settings.unknown: "在文件 发现问题 - 物品 '' 使用了未知的设置类型 ''" +warning.config.item.settings.invulnerable.invalid_damage_source: "在文件 发现问题 - 物品 '' 物品使用了未知的伤害来源类型 '' 允许的来源: []" warning.config.item.missing_material: "在文件 发现问题 - 物品 '' 缺少必需的 'material' 参数" warning.config.item.invalid_material: "在文件 发现问题 - 物品 '' 使用了无效的材料类型 ''" warning.config.item.invalid_custom_model_data: "在文件 发现问题 - 物品 '' 使用了无效的负数模型值 ''." warning.config.item.bad_custom_model_data: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 数值过大 建议使用小于 16,777,216 的值" warning.config.item.custom_model_data_conflict: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 已被物品 '' 占用" +warning.config.item.invalid_component: "在文件 发现问题 - 物品 '' 使用了未知的数据组件 ''" warning.config.item.missing_model_id: "在文件 发现问题 - 物品 '' 缺少必需的 'custom-model-data' 或 'item-model' 参数" warning.config.item.missing_model: "在文件 中发现问题 - 物品 '' 缺少支持 1.21.4+ 资源包必需的 'model' 配置项" warning.config.item.behavior.missing_type: "在文件 发现问题 - 物品 '' 的行为配置缺少必需的 'type' 参数" @@ -349,4 +353,9 @@ warning.config.selector.invalid_type: "在文件 中发现问题 warning.config.selector.invalid_target: "在文件 中发现问题 - 配置项 '' 使用了无效的选择器目标 ''" warning.config.resource_pack.item_model.conflict.vanilla: "无法为 '' 生成物品模型,因为该物品模型已被原版物品占用" warning.config.resource_pack.item_model.already_exist: "无法为 '' 生成物品模型,因为文件 '' 已存在" -warning.config.resource_pack.model.generation.already_exist: "无法生成模型,因为模型文件 '' 已存在" \ No newline at end of file +warning.config.resource_pack.model.generation.already_exist: "无法生成模型,因为模型文件 '' 已存在" +warning.config.resource_pack.generation.missing_font_texture: "字体''缺少必要纹理: ''" +warning.config.resource_pack.generation.missing_model_texture: "模型''缺少纹理''" +warning.config.resource_pack.generation.missing_item_model: "物品''缺少模型文件: ''" +warning.config.resource_pack.generation.missing_block_model: "方块''缺少模型文件: ''" +warning.config.resource_pack.generation.missing_parent_model: "模型''找不到父级模型文件: ''" \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 9d10ade1b..18f604a63 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -20,6 +20,8 @@ dependencies { implementation("net.momirealms:sparrow-nbt-adventure:${rootProject.properties["sparrow_nbt_version"]}") implementation("net.momirealms:sparrow-nbt-codec:${rootProject.properties["sparrow_nbt_version"]}") implementation("net.momirealms:sparrow-nbt-legacy-codec:${rootProject.properties["sparrow_nbt_version"]}") + // S3 + implementation("net.momirealms:craft-engine-s3:0.1") // Util compileOnly("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}") // Adventure @@ -60,8 +62,8 @@ dependencies { compileOnly("com.ezylang:EvalEx:${rootProject.properties["evalex_version"]}") // Jimfs compileOnly("com.google.jimfs:jimfs:${rootProject.properties["jimfs_version"]}") - // S3 - implementation("net.momirealms:craft-engine-s3:0.1") + // Brigadier + compileOnly("com.mojang:brigadier:${rootProject.properties["mojang_brigadier_version"]}") } java { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java index 4192b74c6..cf5321b3c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.util.Key; public class BlockKeys { public static final Key NOTE_BLOCK = Key.of("minecraft:note_block"); + public static final Key TRIPWIRE = Key.of("minecraft:tripwire"); public static final Key CRAFTING_TABLE = Key.of("minecraft:crafting_table"); public static final Key STONECUTTER = Key.of("minecraft:stonecutter"); public static final Key BELL = Key.of("minecraft:bell"); @@ -38,6 +39,7 @@ public class BlockKeys { public static final Key COMMAND_BLOCK = Key.of("minecraft:command_block"); public static final Key CHAIN_COMMAND_BLOCK = Key.of("minecraft:chain_command_block"); public static final Key REPEATING_COMMAND_BLOCK = Key.of("minecraft:repeating_command_block"); + public static final Key DECORATED_POT = Key.of("minecraft:decorated_pot"); public static final Key CAKE = Key.of("minecraft:cake"); public static final Key CANDLE_CAKE = Key.of("minecraft:candle_cake"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java index 72cb6de1c..1b273d9e2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java @@ -17,4 +17,8 @@ public class BlockRegistryMirror { public static int size() { return customBlockStates.length; } + + public static BlockStateWrapper stoneState() { + return stoneState; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/NoteBlockIndicator.java b/core/src/main/java/net/momirealms/craftengine/core/block/ChainUpdateBlockIndicator.java similarity index 52% rename from core/src/main/java/net/momirealms/craftengine/core/block/NoteBlockIndicator.java rename to core/src/main/java/net/momirealms/craftengine/core/block/ChainUpdateBlockIndicator.java index f78f10785..156028f94 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/NoteBlockIndicator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ChainUpdateBlockIndicator.java @@ -1,6 +1,8 @@ package net.momirealms.craftengine.core.block; -public interface NoteBlockIndicator { +public interface ChainUpdateBlockIndicator { boolean isNoteBlock(); + + boolean isTripwire(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractCustomFurniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractCustomFurniture.java index d617a91ac..be342f973 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractCustomFurniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractCustomFurniture.java @@ -64,7 +64,7 @@ public abstract class AbstractCustomFurniture implements CustomFurniture { } @Override - public AnchorType getAnyPlacement() { + public AnchorType getAnyAnchorType() { return this.anyType; } @@ -77,4 +77,13 @@ public abstract class AbstractCustomFurniture implements CustomFurniture { public Placement getPlacement(AnchorType anchorType) { return this.placements.get(anchorType); } + + @Override + public Placement getValidPlacement(AnchorType anchorType) { + Placement placement = this.placements.get(anchorType); + if (placement == null) { + return this.placements.get(getAnyAnchorType()); + } + return placement; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java index d8980df7b..cab15452d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/AbstractFurnitureManager.java @@ -86,11 +86,14 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { @Override public void parseSection(Pack pack, Path path, Key id, Map section) { if (byId.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.furniture.duplicate", path, id); + throw new LocalizedResourceConfigException("warning.config.furniture.duplicate"); } EnumMap placements = new EnumMap<>(AnchorType.class); Map placementMap = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(section.get("placement"), "warning.config.furniture.missing_placement"), false); + if (placementMap.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.furniture.missing_placement"); + } for (Map.Entry entry : placementMap.entrySet()) { // anchor type AnchorType anchorType = AnchorType.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH)); @@ -133,6 +136,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { Map ruleSection = MiscUtils.castToMap(placementArguments.get("rules"), true); if (ruleSection != null) { placements.put(anchorType, new CustomFurniture.Placement( + anchorType, elements.toArray(new FurnitureElement[0]), hitboxes.toArray(new HitBox[0]), ResourceConfigUtils.getOrDefault(ruleSection.get("rotation"), o -> RotationRule.valueOf(o.toString().toUpperCase(Locale.ENGLISH)), RotationRule.ANY), @@ -142,6 +146,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { )); } else { placements.put(anchorType, new CustomFurniture.Placement( + anchorType, elements.toArray(new FurnitureElement[0]), hitboxes.toArray(new HitBox[0]), RotationRule.ANY, diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java index 5357caabb..294e58dda 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java @@ -26,12 +26,14 @@ public interface CustomFurniture { @Nullable LootTable lootTable(); - AnchorType getAnyPlacement(); + AnchorType getAnyAnchorType(); boolean isAllowedPlacement(AnchorType anchorType); Placement getPlacement(AnchorType anchorType); + Placement getValidPlacement(AnchorType anchorType); + interface Builder { Builder id(Key id); @@ -47,7 +49,8 @@ public interface CustomFurniture { CustomFurniture build(); } - record Placement(FurnitureElement[] elements, + record Placement(AnchorType anchorType, + FurnitureElement[] elements, HitBox[] hitBoxes, RotationRule rotationRule, AlignmentRule alignmentRule, diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index 5e0309c97..75b10c4f2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -5,8 +5,10 @@ import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.CooldownData; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.Position; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -81,7 +83,13 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { playSound(sound, 1f, 1f); } - public abstract void playSound(Key sound, float volume, float pitch); + public void playSound(Key sound, float volume, float pitch) { + playSound(sound, SoundSource.MASTER, volume, pitch); + } + + public abstract void playSound(Key sound, SoundSource source, float volume, float pitch); + + public abstract void playSound(Key sound, BlockPos pos, SoundSource source, float volume, float pitch); public abstract void giveItem(Item item); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java index 9f0337be0..b2eebf6c1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java @@ -5,5 +5,5 @@ import net.momirealms.craftengine.core.util.Key; import org.joml.Quaternionf; import org.joml.Vector3f; -public record ProjectileMeta(Key item, ItemDisplayContext displayType, Vector3f scale, Vector3f translation, Quaternionf rotation, String type) { +public record ProjectileMeta(Key item, ItemDisplayContext displayType, Vector3f scale, Vector3f translation, Quaternionf rotation, double range, String type) { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 92ae329cb..4b62d8f22 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -10,7 +10,6 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.*; import org.ahocorasick.trie.Token; import org.ahocorasick.trie.Trie; @@ -44,10 +43,8 @@ public abstract class AbstractFontManager implements FontManager { protected Trie emojiKeywordTrie; protected Map tagMapper; protected Map emojiMapper; - protected List emojiList; protected List allEmojiSuggestions; - protected Set existingImagePaths = new HashSet<>(); public AbstractFontManager(CraftEngine plugin) { this.plugin = plugin; @@ -68,7 +65,6 @@ public abstract class AbstractFontManager implements FontManager { this.images.clear(); this.illegalChars.clear(); this.emojis.clear(); - this.existingImagePaths.clear(); } @Override @@ -269,21 +265,25 @@ public abstract class AbstractFontManager implements FontManager { } private void buildImageTagTrie() { - this.tagMapper = new HashMap<>(); + this.tagMapper = new HashMap<>(1024); for (BitmapImage image : this.images.values()) { String id = image.id().toString(); - this.tagMapper.put(imageTag(id), AdventureHelper.miniMessage().deserialize(image.miniMessage(0, 0))); - this.tagMapper.put("\\" + imageTag(id), Component.text(imageTag(id))); + String simpleImageTag = imageTag(id); + this.tagMapper.put(simpleImageTag, image.componentAt(0, 0)); + this.tagMapper.put("\\" + simpleImageTag, Component.text(simpleImageTag)); for (int i = 0; i < image.rows(); i++) { for (int j = 0; j < image.columns(); j++) { - this.tagMapper.put(imageTag(id + ":" + i + ":" + j), AdventureHelper.miniMessage().deserialize(image.miniMessage(i, j))); - this.tagMapper.put(imageTag("\\" + id + ":" + i + ":" + j), Component.text(imageTag(id + ":" + i + ":" + j))); + String imageArgs = id + ":" + i + ":" + j; + String imageTag = imageTag(imageArgs); + this.tagMapper.put(imageTag, image.componentAt(i, j)); + this.tagMapper.put("\\" + imageTag, Component.text(imageTag)); } } } for (int i = -256; i <= 256; i++) { - this.tagMapper.put("", AdventureHelper.miniMessage().deserialize(this.offsetFont.createOffset(i, FormatUtils::miniMessageFont))); - this.tagMapper.put("\\", Component.text("")); + String shiftTag = ""; + this.tagMapper.put(shiftTag, this.offsetFont.createOffset(i)); + this.tagMapper.put("\\" + shiftTag, Component.text(shiftTag)); } this.imageTagTrie = Trie.builder() .ignoreOverlaps() @@ -377,7 +377,7 @@ public abstract class AbstractFontManager implements FontManager { Key imageId = new Key(split[0], split[1]); Optional bitmapImage = bitmapImageByImageId(imageId); if (bitmapImage.isPresent()) { - image = bitmapImage.get().miniMessage(0, 0); + image = bitmapImage.get().miniMessageAt(0, 0); } else { throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", path, id, rawImage); } @@ -386,7 +386,7 @@ public abstract class AbstractFontManager implements FontManager { Optional bitmapImage = bitmapImageByImageId(imageId); if (bitmapImage.isPresent()) { try { - image = bitmapImage.get().miniMessage(Integer.parseInt(split[2]), Integer.parseInt(split[3])); + image = bitmapImage.get().miniMessageAt(Integer.parseInt(split[2]), Integer.parseInt(split[3])); } catch (ArrayIndexOutOfBoundsException e) { throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", path, id, rawImage); } @@ -468,14 +468,11 @@ public abstract class AbstractFontManager implements FontManager { if (character.startsWith("\\u")) { chars = List.of(CharacterUtils.decodeUnicodeToChars(character)); } else { - if (CharacterUtils.containsCombinedCharacter(character)) { - TranslationManager.instance().log("warning.config.image.invalid_char", path.toString(), id.toString()); - } - StringBuilder stringBuilder = new StringBuilder(); - for (char c : character.toCharArray()) { - stringBuilder.append(String.format("\\u%04x", (int) c)); - } - chars = List.of(CharacterUtils.decodeUnicodeToChars(stringBuilder.toString())); + // ??? TODO 需要测试特殊字符集 +// if (CharacterUtils.containsCombinedCharacter(character)) { +// TranslationManager.instance().log("warning.config.image.invalid_char", path.toString(), id.toString()); +// } + chars = List.of(character.toCharArray()); } } } @@ -506,30 +503,26 @@ public abstract class AbstractFontManager implements FontManager { } Object heightObj = section.get("height"); - if (!resourceLocation.endsWith(".png")) resourceLocation += ".png"; - Key namespacedPath = Key.of(resourceLocation); - Path targetImagePath = pack.resourcePackFolder() - .resolve("assets") - .resolve(namespacedPath.namespace()) - .resolve("textures") - .resolve(namespacedPath.value()); - - if (!doesImageFileExist(targetImagePath)) { -// TranslationManager.instance().log("warning.config.image.file_not_found", path.toString(), id.toString(), targetImagePath.toString()); - // DO NOT RETURN, JUST GIVE WARNINGS - } else if (heightObj == null) { - try (InputStream in = Files.newInputStream(targetImagePath)) { - BufferedImage image = ImageIO.read(in); - heightObj = image.getHeight() / codepointGrid.length; - } catch (IOException e) { - plugin.logger().warn("Failed to load image " + targetImagePath, e); - return; - } - } if (heightObj == null) { - throw new LocalizedResourceConfigException("warning.config.image.missing_height", path, id); + Key namespacedPath = Key.of(resourceLocation); + Path targetImagePath = pack.resourcePackFolder() + .resolve("assets") + .resolve(namespacedPath.namespace()) + .resolve("textures") + .resolve(namespacedPath.value()); + if (Files.exists(targetImagePath)) { + try (InputStream in = Files.newInputStream(targetImagePath)) { + BufferedImage image = ImageIO.read(in); + heightObj = image.getHeight() / codepointGrid.length; + } catch (IOException e) { + plugin.logger().warn("Failed to load image " + targetImagePath, e); + return; + } + } else { + throw new LocalizedResourceConfigException("warning.config.image.missing_height", path, id); + } } int height = ResourceConfigUtils.getAsInt(heightObj, "height"); @@ -541,22 +534,11 @@ public abstract class AbstractFontManager implements FontManager { BitmapImage bitmapImage = new BitmapImage(id, fontKey, height, ascent, resourceLocation, codepointGrid); for (int[] y : codepointGrid) { for (int x : y) { - font.addBitMapImage(x, bitmapImage); + font.addBitmapImage(x, bitmapImage); } } images.put(id, bitmapImage); } - - private boolean doesImageFileExist(Path path) { - if (existingImagePaths.contains(path)) { - return true; - } - boolean exist = Files.exists(path); - if (exist) { - existingImagePaths.add(path); - } - return exist; - } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/BitmapImage.java b/core/src/main/java/net/momirealms/craftengine/core/font/BitmapImage.java index 8272d7419..671a4df05 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/BitmapImage.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/BitmapImage.java @@ -26,9 +26,9 @@ public class BitmapImage implements Supplier { this.codepointGrid = codepointGrid; } - public String miniMessage(int row, int col) { + public String miniMessageAt(int row, int col) { int codepoint = codepointGrid[row][col]; - return FormatUtils.miniMessageFont(new String(Character.toChars(codepoint)), font.toString()); + return FormatUtils.miniMessageFont(new String(Character.toChars(codepoint)), this.font.toString()); } public int height() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/Font.java b/core/src/main/java/net/momirealms/craftengine/core/font/Font.java index cfc1cfab9..87ce3b98d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/Font.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/Font.java @@ -28,7 +28,7 @@ public class Font { return this.idToCodepoint.get(codepoint); } - public void addBitMapImage(int codepoint, BitmapImage image) { + public void addBitmapImage(int codepoint, BitmapImage image) { this.idToCodepoint.put(codepoint, image); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/OffsetFont.java b/core/src/main/java/net/momirealms/craftengine/core/font/OffsetFont.java index eaa5e9444..c1ae43aa3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/OffsetFont.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/OffsetFont.java @@ -3,13 +3,17 @@ package net.momirealms.craftengine.core.font; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import dev.dejvokep.boostedyaml.block.implementation.Section; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.util.CharacterUtils; +import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; public class OffsetFont { private final String font; + private final Key fontKey; private final String NEG_16; private final String NEG_24; @@ -37,6 +41,7 @@ public class OffsetFont { public OffsetFont(Section section) { font = section.getString("font", "minecraft:default"); + fontKey = Key.key(font); NEG_16 = convertIfUnicode(section.getString("-16", "")); NEG_24 = convertIfUnicode(section.getString("-24", "")); @@ -59,16 +64,14 @@ public class OffsetFont { } } + public Component createOffset(int offset) { + if (offset == 0) return Component.empty(); + return Component.text(Objects.requireNonNull(this.fastLookup.get(offset, k -> k > 0 ? createPos(k) : createNeg(-k)))).font(this.fontKey); + } + public String createOffset(int offset, BiFunction tagDecorator) { if (offset == 0) return ""; - String raw = fastLookup.get(offset, k -> { - if (k > 0) { - return createPos(k); - } else { - return createNeg(-k); - } - }); - return tagDecorator.apply(raw, font); + return tagDecorator.apply(this.fastLookup.get(offset, k -> k > 0 ? createPos(k) : createNeg(-k)), this.font); } @SuppressWarnings("DuplicatedCode") diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java index e774f409a..06b87e5b2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractCustomItem.java @@ -18,6 +18,7 @@ import java.util.Optional; public abstract class AbstractCustomItem implements CustomItem { protected final Holder id; protected final Key material; + protected final Key clientBoundMaterial; protected final ItemDataModifier[] modifiers; protected final Map> modifierMap; protected final ItemDataModifier[] clientBoundModifiers; @@ -27,7 +28,7 @@ public abstract class AbstractCustomItem implements CustomItem { protected final Map>> events; @SuppressWarnings("unchecked") - public AbstractCustomItem(Holder id, Key material, + public AbstractCustomItem(Holder id, Key material, Key clientBoundMaterial, List behaviors, List> modifiers, List> clientBoundModifiers, @@ -35,6 +36,7 @@ public abstract class AbstractCustomItem implements CustomItem { Map>> events) { this.id = id; this.material = material; + this.clientBoundMaterial = clientBoundMaterial; this.events = events; // unchecked cast this.modifiers = modifiers.toArray(new ItemDataModifier[0]); @@ -74,6 +76,11 @@ public abstract class AbstractCustomItem implements CustomItem { return this.material; } + @Override + public Key clientBoundMaterial() { + return this.clientBoundMaterial; + } + @Override public ItemDataModifier[] dataModifiers() { return this.modifiers; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index 48e4b70af..219dd5e3f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.Tag; @@ -423,6 +424,16 @@ public class AbstractItem, I> implements Item { return new AbstractItem<>(this.factory, this.factory.mergeCopy(this.item, (W) ((AbstractItem) another).item)); } + @Override + public AbstractItem transmuteCopy(Key another, int count) { + return new AbstractItem<>(this.factory, this.factory.transmuteCopy(this.item, another, count)); + } + + @Override + public Item unsafeTransmuteCopy(Object another, int count) { + return new AbstractItem<>(this.factory, this.factory.unsafeTransmuteCopy(this.item, another, count)); + } + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public void merge(Item another) { @@ -433,4 +444,9 @@ public class AbstractItem, I> implements Item { public byte[] toByteArray() { return this.factory.toByteArray(this.item); } + + @Override + public void shrink(int amount) { + this.item.shrink(amount); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 1615d4fcb..39d2189ef 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviors; import net.momirealms.craftengine.core.item.modifier.*; +import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.ResourceLocation; @@ -26,6 +27,7 @@ import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.type.Either; +import org.joml.Vector3f; import java.nio.file.Path; import java.util.*; @@ -66,9 +68,10 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl this.equipmentsToGenerate = new HashSet<>(); } - protected void registerDataFunction(Function> function, String... alias) { + @Override + public void registerDataType(Function> factory, String... alias) { for (String a : alias) { - dataFunctions.put(a, function); + dataFunctions.put(a, factory); } } @@ -256,7 +259,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return VANILLA_ITEMS.contains(item); } - protected abstract CustomItem.Builder createPlatformItemBuilder(Holder id, Key material); + protected abstract CustomItem.Builder createPlatformItemBuilder(Holder id, Key material, Key clientBoundMaterial); public class ItemParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; @@ -294,6 +297,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl boolean isVanillaItem = isVanillaItem(id); Key material = Key.from(isVanillaItem ? id.value() : ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("material"), "warning.config.item.missing_material").toLowerCase(Locale.ENGLISH)); + Key clientBoundMaterial = section.containsKey("client-bound-material") ? Key.from(section.get("client-bound-material").toString().toLowerCase(Locale.ENGLISH)) : material; int customModelData = ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data"); if (customModelData < 0) { throw new LocalizedResourceConfigException("warning.config.item.invalid_custom_model_data", String.valueOf(customModelData)); @@ -304,7 +308,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl Key itemModelKey = null; - CustomItem.Builder itemBuilder = createPlatformItemBuilder(holder, material); + CustomItem.Builder itemBuilder = createPlatformItemBuilder(holder, material, clientBoundMaterial); boolean hasItemModelSection = section.containsKey("item-model"); // To get at least one model provider @@ -389,7 +393,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides()); } else { legacyOverridesModels = new TreeSet<>(); - processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, material, customModelData); + processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, clientBoundMaterial, customModelData); if (legacyOverridesModels.isEmpty()) { TranslationManager.instance().log("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString()); } @@ -400,18 +404,18 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl if (customModelData != 0) { // use custom model data // check conflict - Map conflict = AbstractItemManager.this.cmdConflictChecker.computeIfAbsent(material, k -> new HashMap<>()); + Map conflict = AbstractItemManager.this.cmdConflictChecker.computeIfAbsent(clientBoundMaterial, k -> new HashMap<>()); if (conflict.containsKey(customModelData)) { throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(customModelData), conflict.get(customModelData).toString()); } conflict.put(customModelData, id); // Parse models if (isModernFormatRequired() && modernModel != null) { - TreeMap map = AbstractItemManager.this.modernOverrides.computeIfAbsent(material, k -> new TreeMap<>()); + TreeMap map = AbstractItemManager.this.modernOverrides.computeIfAbsent(clientBoundMaterial, k -> new TreeMap<>()); map.put(customModelData, modernModel); } if (needsLegacyCompatibility() && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { - TreeSet lom = AbstractItemManager.this.legacyOverrides.computeIfAbsent(material, k -> new TreeSet<>()); + TreeSet lom = AbstractItemManager.this.legacyOverrides.computeIfAbsent(clientBoundMaterial, k -> new TreeSet<>()); lom.addAll(legacyOverridesModels); } } @@ -430,34 +434,51 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } private void registerFunctions() { - registerDataFunction((obj) -> { + registerDataType((obj) -> { Map data = MiscUtils.castToMap(obj, false); String plugin = data.get("plugin").toString(); String id = data.get("id").toString(); ExternalItemProvider provider = AbstractItemManager.this.getExternalItemProvider(plugin); return new ExternalModifier<>(id, Objects.requireNonNull(provider, "Item provider " + plugin + " not found")); }, "external"); - registerDataFunction((obj) -> { + registerDataType((obj) -> { String name = obj.toString(); - return new CustomNameModifier<>(name); + return new CustomNameModifier<>(Config.nonItalic() ? "" + name : name); }, "custom-name"); - registerDataFunction((obj) -> { + registerDataType((obj) -> { String name = obj.toString(); - return new ItemNameModifier<>(name); + return new ItemNameModifier<>(Config.nonItalic() ? "" + name : name); }, "item-name", "display-name"); - registerDataFunction((obj) -> { - List name = MiscUtils.getAsStringList(obj); - return new LoreModifier<>(name); + registerDataType((obj) -> { + List lore = MiscUtils.getAsStringList(obj).stream().map(it -> "" + it).toList(); + return new LoreModifier<>(lore); }, "lore", "display-lore", "description"); - registerDataFunction((obj) -> { + registerDataType((obj) -> { + Map> dynamicLore = new LinkedHashMap<>(); + if (obj instanceof Map map) { + for (Map.Entry entry : map.entrySet()) { + dynamicLore.put(entry.getKey().toString(), MiscUtils.getAsStringList(entry.getValue())); + } + } + return new DynamicLoreModifier<>(dynamicLore); + }, "dynamic-lore"); + registerDataType((obj) -> { + if (obj instanceof Integer integer) { + return new DyedColorModifier<>(integer); + } else { + Vector3f vector3f = MiscUtils.getAsVector3f(obj, "dyed-color"); + return new DyedColorModifier<>(MCUtils.fastFloor(vector3f.x) << 16 + MCUtils.fastFloor(vector3f.y) << 8 + MCUtils.fastFloor(vector3f.z)); + } + }, "dyed-color"); + registerDataType((obj) -> { Map data = MiscUtils.castToMap(obj, false); return new TagsModifier<>(data); }, "tags", "tag", "nbt"); - registerDataFunction((obj) -> { + registerDataType((obj) -> { boolean value = TypeUtils.checkType(obj, Boolean.class); return new UnbreakableModifier<>(value); }, "unbreakable"); - registerDataFunction((obj) -> { + registerDataType((obj) -> { Map data = MiscUtils.castToMap(obj, false); List enchantments = new ArrayList<>(); for (Map.Entry e : data.entrySet()) { @@ -467,41 +488,47 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } return new EnchantmentModifier<>(enchantments); }, "enchantment", "enchantments", "enchant"); - registerDataFunction((obj) -> { + registerDataType((obj) -> { Map data = MiscUtils.castToMap(obj, false); String material = data.get("material").toString().toLowerCase(Locale.ENGLISH); String pattern = data.get("pattern").toString().toLowerCase(Locale.ENGLISH); return new TrimModifier<>(material, pattern); }, "trim"); if (VersionHelper.isOrAbove1_20_5()) { - registerDataFunction((obj) -> { + registerDataType((obj) -> { Map data = MiscUtils.castToMap(obj, false); return new ComponentModifier<>(data); }, "components", "component"); - registerDataFunction((obj) -> { + registerDataType((obj) -> { List data = MiscUtils.getAsStringList(obj); return new RemoveComponentModifier<>(data); }, "remove-components", "remove-component"); + registerDataType((obj) -> { + Map data = MiscUtils.castToMap(obj, false); + int nutrition = ResourceConfigUtils.getAsInt(data.get("nutrition"), "nutrition"); + float saturation = ResourceConfigUtils.getAsFloat(data.get("saturation"), "saturation"); + return new FoodModifier<>(nutrition, saturation, (boolean) data.getOrDefault("can-always-eat", false)); + }, "food"); } if (VersionHelper.isOrAbove1_21()) { - registerDataFunction((obj) -> { + registerDataType((obj) -> { String song = obj.toString(); return new JukeboxSongModifier<>(new JukeboxPlayable(song, true)); }, "jukebox-playable"); } if (VersionHelper.isOrAbove1_21_2()) { - registerDataFunction((obj) -> { + registerDataType((obj) -> { String id = obj.toString(); return new TooltipStyleModifier<>(Key.of(id)); }, "tooltip-style"); } if (VersionHelper.isOrAbove1_21_2()) { - registerDataFunction((obj) -> { + registerDataType((obj) -> { Map data = MiscUtils.castToMap(obj, false); return new EquippableModifier<>(EquipmentData.fromMap(data)); }, "equippable"); } - registerDataFunction((obj) -> { + registerDataType((obj) -> { Map data = MiscUtils.castToMap(obj, false); Map arguments = new HashMap<>(); for (Map.Entry entry : data.entrySet()) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java index 813ac6486..40e402bff 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ComponentKeys.java @@ -26,4 +26,5 @@ public final class ComponentKeys { public static final Key PROFILE = Key.of("minecraft", "profile"); public static final Key DYED_COLOR = Key.of("minecraft", "dyed_color"); public static final Key DEATH_PROTECTION = Key.of("minecraft", "death_protection"); + public static final Key FOOD = Key.of("minecraft", "food"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index 89078fb27..01512fa5a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; @@ -21,6 +22,8 @@ public interface CustomItem extends BuildableItem { Key material(); + Key clientBoundMaterial(); + ItemDataModifier[] dataModifiers(); Map> dataModifierMap(); @@ -51,6 +54,8 @@ public interface CustomItem extends BuildableItem { interface Builder { Builder id(Holder id); + Builder clientBoundMaterial(Key clientBoundMaterialKey); + Builder material(Key material); Builder dataModifier(ItemDataModifier modifier); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index 26f3f39e8..8b2954c31 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -3,6 +3,8 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.Tag; @@ -177,7 +179,21 @@ public interface Item { Item mergeCopy(Item another); + Item transmuteCopy(Key another, int count); + + Item unsafeTransmuteCopy(Object another, int count); + + void shrink(int amount); + + default Item transmuteCopy(Key another) { + return transmuteCopy(another, this.count()); + } + void merge(Item another); + default Item apply(ItemDataModifier modifier, ItemBuildContext context) { + return modifier.apply(this, context); + } + byte[] toByteArray(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index b27853e93..783bf3365 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.item; import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; @@ -193,4 +194,8 @@ public abstract class ItemFactory, I> { protected abstract void setJsonComponent(W item, Object type, JsonElement value); protected abstract void setNBTComponent(W item, Object type, Tag value); + + protected abstract W transmuteCopy(W item, Key newItem, int amount); + + protected abstract W unsafeTransmuteCopy(W item, Object newItem, int count); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index d8419d2ea..a90a44e69 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.util.Key; public class ItemKeys { public static final Key AIR = Key.of("minecraft:air"); + public static final Key FLINT_AND_STEEL = Key.of("minecraft:flint_and_steel"); public static final Key STONE = Key.of("minecraft:stone"); public static final Key TRIDENT = Key.of("minecraft:trident"); public static final Key SHIELD = Key.of("minecraft:shield"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index 0ab35daea..4aaf4e6df 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; import net.momirealms.craftengine.core.pack.model.ItemModel; import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel; @@ -14,9 +15,12 @@ import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.function.Function; public interface ItemManager extends Manageable, ModelGenerator { + void registerDataType(Function> factory, String... alias); + ConfigParser parser(); Map> legacyItemOverrides(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java index a9f93ebb5..7136f8b50 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java @@ -3,14 +3,16 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.item.modifier.EquippableModifier; +import net.momirealms.craftengine.core.item.modifier.FoodModifier; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.item.setting.AnvilRepairItem; +import net.momirealms.craftengine.core.item.setting.EquipmentData; +import net.momirealms.craftengine.core.item.setting.FoodData; +import net.momirealms.craftengine.core.item.setting.Helmet; import net.momirealms.craftengine.core.pack.misc.EquipmentGeneration; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.sound.SoundData; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.util.*; import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -30,13 +32,21 @@ public class ItemSettings { ProjectileMeta projectileMeta; boolean dyeable = true; Helmet helmet = null; + FoodData foodData = null; + Key consumeReplacement = null; + Key craftRemainder = null; + List invulnerable = List.of(); private ItemSettings() {} public List> modifiers() { ArrayList> modifiers = new ArrayList<>(); - if (VersionHelper.isOrAbove1_21_2() && this.equipment != null && this.equipment.modernData() != null) modifiers.add(new EquippableModifier<>(this.equipment.modernData())); - // TODO 1.20 leather armor + if (VersionHelper.isOrAbove1_21_2() && this.equipment != null && this.equipment.modernData() != null) { + modifiers.add(new EquippableModifier<>(this.equipment.modernData())); + } + if (VersionHelper.isOrAbove1_20_5() && this.foodData != null) { + modifiers.add(new FoodModifier<>(this.foodData.nutrition(), this.foodData.saturation(), false)); + } return modifiers; } @@ -60,6 +70,11 @@ public class ItemSettings { newSettings.canPlaceRelatedVanillaBlock = settings.canPlaceRelatedVanillaBlock; newSettings.projectileMeta = settings.projectileMeta; newSettings.dyeable = settings.dyeable; + newSettings.helmet = settings.helmet; + newSettings.foodData = settings.foodData; + newSettings.consumeReplacement = settings.consumeReplacement; + newSettings.craftRemainder = settings.craftRemainder; + newSettings.invulnerable = settings.invulnerable; return newSettings; } @@ -107,6 +122,21 @@ public class ItemSettings { return anvilRepairItems; } + @Nullable + public FoodData foodData() { + return foodData; + } + + @Nullable + public Key consumeReplacement() { + return consumeReplacement; + } + + @Nullable + public Key craftRemainder() { + return craftRemainder; + } + @Nullable public Helmet helmet() { return helmet; @@ -117,11 +147,25 @@ public class ItemSettings { return equipment; } + public List invulnerable() { + return invulnerable; + } + public ItemSettings repairItems(List items) { this.anvilRepairItems = items; return this; } + public ItemSettings consumeReplacement(Key key) { + this.consumeReplacement = key; + return this; + } + + public ItemSettings craftRemainder(Key key) { + this.craftRemainder = key; + return this; + } + public ItemSettings canRepair(boolean canRepair) { this.canRepair = canRepair; return this; @@ -152,6 +196,11 @@ public class ItemSettings { return this; } + public ItemSettings foodData(FoodData foodData) { + this.foodData = foodData; + return this; + } + public ItemSettings equipment(EquipmentGeneration equipment) { this.equipment = equipment; return this; @@ -167,6 +216,11 @@ public class ItemSettings { return this; } + public ItemSettings invulnerable(List invulnerable) { + this.invulnerable = invulnerable; + return this; + } + @FunctionalInterface public interface Modifier { @@ -206,6 +260,14 @@ public class ItemSettings { int intValue = ResourceConfigUtils.getAsInt(value, "fuel-time"); return settings -> settings.fuelTime(intValue); })); + registerFactory("consume-replacement", (value -> settings -> { + if (value == null) settings.consumeReplacement(null); + else settings.consumeReplacement(Key.of(value.toString())); + })); + registerFactory("craft-remaining-item", (value -> settings -> { + if (value == null) settings.craftRemainder(null); + else settings.craftRemainder(Key.of(value.toString())); + })); registerFactory("tags", (value -> { List tags = MiscUtils.getAsStringList(value); return settings -> settings.tags(tags.stream().map(Key::of).collect(Collectors.toSet())); @@ -239,7 +301,8 @@ public class ItemSettings { Vector3f scale = MiscUtils.getAsVector3f(args.getOrDefault("scale", "1"), "scale"); Quaternionf rotation = MiscUtils.getAsQuaternionf(ResourceConfigUtils.get(args, "rotation-left", "rotation"), "rotation-left"); String type = args.getOrDefault("type", "none").toString(); - return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, scale, translation, rotation, type)); + double range = ResourceConfigUtils.getAsDouble(args.getOrDefault("range", 1), "range"); + return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, scale, translation, rotation, range, type)); })); registerFactory("helmet", (value -> { Map args = MiscUtils.castToMap(value, false); @@ -249,6 +312,24 @@ public class ItemSettings { boolean bool = (boolean) value; return settings -> settings.dyeable(bool); })); + registerFactory("food", (value -> { + Map args = MiscUtils.castToMap(value, false); + FoodData data = new FoodData( + ResourceConfigUtils.getAsInt(args.get("nutrition"), "nutrition"), + ResourceConfigUtils.getAsFloat(args.get("saturation"), "saturation") + ); + return settings -> settings.foodData(data); + })); + registerFactory("invulnerable", (value -> { + List list = MiscUtils.getAsStringList(value).stream().map(it -> { + DamageSource source = DamageSource.byName(it); + if (source == null) { + throw new LocalizedResourceConfigException("warning.config.item.settings.invulnerable.invalid_damage_source", it, EnumUtils.toString(DamageSource.values())); + } + return source; + }).toList(); + return settings -> settings.invulnerable(list); + })); } private static void registerFactory(String id, ItemSettings.Modifier.Factory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemWrapper.java index 5383fb97c..27164ea29 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemWrapper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemWrapper.java @@ -13,4 +13,6 @@ public interface ItemWrapper { void count(int amount); ItemWrapper copyWithCount(int count); + + void shrink(int amount); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentModifier.java index 19b4f6af7..a3ec03e7d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ArgumentModifier.java @@ -26,7 +26,7 @@ public class ArgumentModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { if (VersionHelper.isOrAbove1_20_5()) { CompoundTag customData = (CompoundTag) Optional.ofNullable(item.getNBTComponent(ComponentKeys.CUSTOM_DATA)).orElse(new CompoundTag()); CompoundTag argumentTag = new CompoundTag(); @@ -42,5 +42,6 @@ public class ArgumentModifier implements ItemDataModifier { } item.setTag(processed, ARGUMENTS_TAG); } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java index 5c769b2bc..5fb24fa13 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentModifier.java @@ -63,7 +63,7 @@ public class ComponentModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { for (Pair entry : this.arguments) { item.setComponent(entry.left(), entry.right()); } @@ -75,10 +75,11 @@ public class ComponentModifier implements ItemDataModifier { item.setComponent(ComponentKeys.CUSTOM_DATA, this.customData); } } + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { for (Pair entry : this.arguments) { Tag previous = item.getNBTComponent(entry.left()); if (previous != null) { @@ -87,5 +88,6 @@ public class ComponentModifier implements ItemDataModifier { networkData.put(entry.left().asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java index fb6ec08d1..9634a56c1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomModelDataModifier.java @@ -21,12 +21,13 @@ public class CustomModelDataModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.customModelData(argument); + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { Tag previous = item.getNBTComponent(ComponentKeys.CUSTOM_MODEL_DATA); if (previous != null) { @@ -42,5 +43,6 @@ public class CustomModelDataModifier implements ItemDataModifier { networkData.put("CustomModelData", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java index d16b5281b..ae46ebae5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; @@ -14,7 +13,7 @@ public class CustomNameModifier implements ItemDataModifier { private final String argument; public CustomNameModifier(String argument) { - this.argument = Config.nonItalic() ? "" + argument : argument; + this.argument = argument; } @Override @@ -23,12 +22,13 @@ public class CustomNameModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.customNameComponent(AdventureHelper.miniMessage().deserialize(this.argument, context.tagResolvers())); + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { Tag previous = item.getNBTComponent(ComponentKeys.CUSTOM_NAME); if (previous != null) { @@ -44,5 +44,6 @@ public class CustomNameModifier implements ItemDataModifier { networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java new file mode 100644 index 000000000..d85b3133e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DyedColorModifier.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +public class DyedColorModifier implements ItemDataModifier { + private final int color; + + public DyedColorModifier(int color) { + this.color = color; + } + + @Override + public String name() { + return "dyed-color"; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + item.dyedColor(this.color); + return item; + } + + @Override + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.DYED_COLOR); + if (previous != null) { + networkData.put(ComponentKeys.DYED_COLOR.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.DYED_COLOR.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } else { + Tag previous = item.getNBTTag("display", "color"); + if (previous != null) { + networkData.put("display.color", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("display.color", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + return item; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java new file mode 100644 index 000000000..01e8d92be --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java @@ -0,0 +1,60 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class DynamicLoreModifier implements ItemDataModifier { + private final Map> displayContexts; + private final String defaultContext; + + public DynamicLoreModifier(Map> displayContexts) { + this.defaultContext = displayContexts.keySet().iterator().next(); + this.displayContexts = displayContexts; + } + + @Override + public String name() { + return "dynamic-lore"; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + String displayContext = Optional.ofNullable(item.getJavaTag("craftengine:display_context")).orElse(this.defaultContext).toString(); + List lore = this.displayContexts.get(displayContext); + if (lore == null) { + lore = this.displayContexts.get(this.defaultContext); + } + item.loreComponent(lore.stream().map(it -> AdventureHelper.miniMessage().deserialize(it, context.tagResolvers())).toList()); + return item; + } + + @Override + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.LORE); + if (previous != null) { + networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } else { + Tag previous = item.getNBTTag("display", "Lore"); + if (previous != null) { + networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + return item; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java index 88a06c183..5c617a814 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentModifier.java @@ -20,16 +20,17 @@ public class EnchantmentModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { item.setStoredEnchantments(this.enchantments); } else { item.setEnchantments(this.enchantments); } + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { if (VersionHelper.isOrAbove1_20_5()) { Tag previous = item.getNBTComponent(ComponentKeys.STORED_ENCHANTMENTS); @@ -63,5 +64,6 @@ public class EnchantmentModifier implements ItemDataModifier { } } } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java index 52845cb07..9851c1141 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableModifier.java @@ -1,8 +1,8 @@ package net.momirealms.craftengine.core.item.modifier; -import net.momirealms.craftengine.core.item.EquipmentData; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.setting.EquipmentData; public class EquippableModifier implements ItemDataModifier { private final EquipmentData data; @@ -17,7 +17,8 @@ public class EquippableModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.equippable(this.data); + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java index 0cf95a6e1..95c52bd45 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java @@ -21,13 +21,14 @@ public class ExternalModifier implements ItemDataModifier { @SuppressWarnings("unchecked") @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { I another = this.provider.build(id, context); if (another == null) { CraftEngine.instance().logger().warn("'" + id + "' could not be found in " + provider.plugin()); - return; + return item; } Item anotherWrapped = (Item) CraftEngine.instance().itemManager().wrap(another); item.merge(anotherWrapped); + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/FoodModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/FoodModifier.java new file mode 100644 index 000000000..38fc4232b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/FoodModifier.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +import java.util.Map; + +public class FoodModifier implements ItemDataModifier { + private final int nutrition; + private final float saturation; + private final boolean canAlwaysEat; + + public FoodModifier(int nutrition, float saturation, boolean canAlwaysEat) { + this.canAlwaysEat = canAlwaysEat; + this.nutrition = nutrition; + this.saturation = saturation; + } + + @Override + public String name() { + return "food"; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + item.setJavaComponent(ComponentKeys.FOOD, Map.of( + "nutrition", this.nutrition, + "saturation", this.saturation, + "can_always_eat", this.canAlwaysEat + )); + return item; + } + + @Override + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + Tag previous = item.getNBTComponent(ComponentKeys.FOOD); + if (previous != null) { + networkData.put(ComponentKeys.FOOD.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.FOOD.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + return item; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java index e82c960dc..690236b87 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/IdModifier.java @@ -18,7 +18,8 @@ public class IdModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.customId(this.argument); + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java index 73720c53a..2ffe87f59 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifier.java @@ -8,8 +8,9 @@ public interface ItemDataModifier { String name(); - void apply(Item item, ItemBuildContext context); + Item apply(Item item, ItemBuildContext context); - default void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + default Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java index 537ed5aee..0d4cea04d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemModelModifier.java @@ -21,17 +21,19 @@ public class ItemModelModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.itemModel(this.data.toString()); + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { Tag previous = item.getNBTComponent(ComponentKeys.ITEM_MODEL); if (previous != null) { networkData.put(ComponentKeys.ITEM_MODEL.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { networkData.put(ComponentKeys.ITEM_MODEL.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java index f59c44abb..0171474e1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; @@ -14,7 +13,7 @@ public class ItemNameModifier implements ItemDataModifier { private final String argument; public ItemNameModifier(String argument) { - this.argument = Config.nonItalic() ? "" + argument : argument; + this.argument = argument; } @Override @@ -23,12 +22,13 @@ public class ItemNameModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.itemNameComponent(AdventureHelper.miniMessage().deserialize(this.argument, context.tagResolvers())); + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { Tag previous = item.getNBTComponent(ComponentKeys.ITEM_NAME); if (previous != null) { @@ -44,5 +44,6 @@ public class ItemNameModifier implements ItemDataModifier { networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java index b8523edd2..2513d6f3a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/JukeboxSongModifier.java @@ -17,7 +17,8 @@ public class JukeboxSongModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.jukeboxSong(this.song); + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java index 6328fe5c8..dd5816861 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; @@ -16,7 +15,7 @@ public class LoreModifier implements ItemDataModifier { private final List argument; public LoreModifier(List argument) { - this.argument = Config.nonItalic() ? argument.stream().map(it -> "" + it).toList() : argument; + this.argument = argument; } @Override @@ -25,13 +24,13 @@ public class LoreModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { - item.loreComponent(this.argument.stream().map(it -> AdventureHelper.miniMessage().deserialize( - it, context.tagResolvers())).toList()); + public Item apply(Item item, ItemBuildContext context) { + item.loreComponent(this.argument.stream().map(it -> AdventureHelper.miniMessage().deserialize(it, context.tagResolvers())).toList()); + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { Tag previous = item.getNBTComponent(ComponentKeys.LORE); if (previous != null) { @@ -47,5 +46,6 @@ public class LoreModifier implements ItemDataModifier { networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java index 90dbb508c..f6461e772 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/RemoveComponentModifier.java @@ -26,19 +26,21 @@ public class RemoveComponentModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { for (String argument : this.arguments) { item.removeComponent(argument); } + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { for (String component : this.arguments) { Tag previous = item.getNBTComponent(component); if (previous != null) { networkData.put(component, NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java index 582fce937..34aaa3ffa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TagsModifier.java @@ -28,17 +28,18 @@ public class TagsModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { for (Map.Entry entry : this.arguments.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); item.setTag(value, key); } + return item; } // TODO NOT PERFECT @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { for (Map.Entry entry : this.arguments.entrySet()) { Tag previous = item.getNBTTag(entry.getKey()); if (previous != null) { @@ -47,6 +48,7 @@ public class TagsModifier implements ItemDataModifier { networkData.put(entry.getKey(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } + return item; } private static Map mapToMap(final Map source) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java index de060f05d..af066a977 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TooltipStyleModifier.java @@ -21,17 +21,19 @@ public class TooltipStyleModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.tooltipStyle(argument.toString()); + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { Tag previous = item.getNBTComponent(ComponentKeys.TOOLTIP_STYLE); if (previous != null) { networkData.put(ComponentKeys.TOOLTIP_STYLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { networkData.put(ComponentKeys.TOOLTIP_STYLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java index 4d8a4facd..99ac6a9df 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/TrimModifier.java @@ -20,12 +20,13 @@ public class TrimModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.trim(new Trim(this.material, this.pattern)); + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { Tag previous = item.getNBTComponent(ComponentKeys.TRIM); if (previous != null) { @@ -41,5 +42,6 @@ public class TrimModifier implements ItemDataModifier { networkData.put("Trim", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java index 34c58ed56..756152329 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/UnbreakableModifier.java @@ -21,12 +21,13 @@ public class UnbreakableModifier implements ItemDataModifier { } @Override - public void apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.unbreakable(this.argument); + return item; } @Override - public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { Tag previous = item.getNBTComponent(ComponentKeys.UNBREAKABLE); if (previous != null) { @@ -42,5 +43,6 @@ public class UnbreakableModifier implements ItemDataModifier { networkData.put("Unbreakable", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } + return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java index f84e496ec..280e6b7e3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java @@ -27,7 +27,8 @@ public abstract class AbstractRecipeManager implements RecipeManager { protected final Map>> byIngredient = new HashMap<>(); protected final Set dataPackRecipes = new HashSet<>(); protected final Set customRecipes = new HashSet<>(); - private final RecipeParser recipeParser; + protected final RecipeParser recipeParser; + protected boolean isReloading; public AbstractRecipeManager() { this.recipeReader = initVanillaRecipeReader(); @@ -72,37 +73,44 @@ public abstract class AbstractRecipeManager implements RecipeManager { @Override public boolean isDataPackRecipe(Key key) { + if (this.isReloading) return false; return this.dataPackRecipes.contains(key); } @Override public boolean isCustomRecipe(Key key) { + if (this.isReloading) return false; return this.byId.containsKey(key); } @Override public Optional> recipeById(Key key) { + if (this.isReloading) return Optional.empty(); return Optional.ofNullable(this.byId.get(key)); } @Override public List> recipesByType(Key type) { + if (this.isReloading) return List.of(); return this.byType.getOrDefault(type, List.of()); } @Override public List> recipeByResult(Key result) { + if (this.isReloading) return List.of(); return this.byResult.getOrDefault(result, List.of()); } @Override public List> recipeByIngredient(Key ingredient) { + if (this.isReloading) return List.of(); return this.byIngredient.getOrDefault(ingredient, List.of()); } @Nullable @Override public Recipe recipeByInput(Key type, RecipeInput input) { + if (this.isReloading) return null; List> recipes = this.byType.get(type); if (recipes == null) return null; for (Recipe recipe : recipes) { @@ -116,8 +124,9 @@ public abstract class AbstractRecipeManager implements RecipeManager { @Nullable @Override public Recipe recipeByInput(Key type, RecipeInput input, Key lastRecipe) { + if (this.isReloading) return null; if (lastRecipe != null) { - Recipe last = byId.get(lastRecipe); + Recipe last = this.byId.get(lastRecipe); if (last != null && last.matches(input)) { return last; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AnvilRepairItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/setting/AnvilRepairItem.java similarity index 66% rename from core/src/main/java/net/momirealms/craftengine/core/item/AnvilRepairItem.java rename to core/src/main/java/net/momirealms/craftengine/core/item/setting/AnvilRepairItem.java index 8ea18261d..650624de3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AnvilRepairItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/setting/AnvilRepairItem.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.item; +package net.momirealms.craftengine.core.item.setting; import java.util.List; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/EquipmentData.java b/core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java similarity index 98% rename from core/src/main/java/net/momirealms/craftengine/core/item/EquipmentData.java rename to core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java index 2a33f07df..aa371660c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/EquipmentData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.item; +package net.momirealms.craftengine.core.item.setting; import net.momirealms.craftengine.core.entity.EquipmentSlot; import net.momirealms.craftengine.core.util.Key; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/setting/FoodData.java b/core/src/main/java/net/momirealms/craftengine/core/item/setting/FoodData.java new file mode 100644 index 000000000..bf69775dc --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/setting/FoodData.java @@ -0,0 +1,19 @@ +package net.momirealms.craftengine.core.item.setting; + +public class FoodData { + private final int nutrition; + private final float saturation; + + public FoodData(int nutrition, float saturation) { + this.nutrition = nutrition; + this.saturation = saturation; + } + + public int nutrition() { + return nutrition; + } + + public float saturation() { + return saturation; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Helmet.java b/core/src/main/java/net/momirealms/craftengine/core/item/setting/Helmet.java similarity index 83% rename from core/src/main/java/net/momirealms/craftengine/core/item/Helmet.java rename to core/src/main/java/net/momirealms/craftengine/core/item/setting/Helmet.java index 0235c411e..231839c1b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Helmet.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/setting/Helmet.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.item; +package net.momirealms.craftengine.core.item.setting; import net.momirealms.craftengine.core.sound.SoundData; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 4ec3ffd9b..5b8093283 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.core.pack; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; import com.google.gson.*; @@ -8,7 +10,7 @@ import dev.dejvokep.boostedyaml.block.implementation.Section; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.momirealms.craftengine.core.font.BitmapImage; import net.momirealms.craftengine.core.font.Font; -import net.momirealms.craftengine.core.item.EquipmentData; +import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.pack.conflict.PathContext; import net.momirealms.craftengine.core.pack.conflict.resolution.ResolutionConditional; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; @@ -57,10 +59,11 @@ public abstract class AbstractPackManager implements PackManager { public static final Map PRESET_LEGACY_MODELS_ITEM = new HashMap<>(); public static final Map PRESET_MODELS_BLOCK = new HashMap<>(); public static final Map PRESET_ITEMS = new HashMap<>(); - public static final Set VANILLA_ITEM_TEXTURES = new HashSet<>(); - public static final Set VANILLA_BLOCK_TEXTURES = new HashSet<>(); - public static final Set VANILLA_FONT_TEXTURES = new HashSet<>(); + public static final Set VANILLA_TEXTURES = new HashSet<>(); + public static final Set VANILLA_MODELS = new HashSet<>(); private static final byte[] EMPTY_IMAGE; + private static final String[] TRIM_ITEMS = {"boots_trim","chestplate_trim","helmet_trim","leggings_trim"}; + private static final String[] TRIM_COLOR_PALETTES = {"amethyst","copper","diamond","diamond_darker","emerald","gold","gold_darker","iron","iron_darker","lapis","netherite","netherite_darker","quartz","redstone","resin","trim_palette"}; static { var stream = new ByteArrayOutputStream(); try { @@ -98,13 +101,25 @@ public abstract class AbstractPackManager implements PackManager { private void initInternalData() { loadInternalData("internal/models/item/legacy/_all.json", PRESET_LEGACY_MODELS_ITEM::put); - loadInternalData("internal/models/item/modern/_all.json", PRESET_MODERN_MODELS_ITEM::put); + loadInternalData("internal/models/item/_all.json", PRESET_MODERN_MODELS_ITEM::put); loadInternalData("internal/models/block/_all.json", PRESET_MODELS_BLOCK::put); loadInternalData("internal/items/_all.json", PRESET_ITEMS::put); - loadInternalList("internal/textures/block/_list.json", VANILLA_BLOCK_TEXTURES::add); - loadInternalList("internal/textures/item/_list.json", VANILLA_ITEM_TEXTURES::add); - loadInternalList("internal/textures/font/_list.json", VANILLA_FONT_TEXTURES::add); + loadInternalList("textures", "block/", VANILLA_TEXTURES::add); + loadInternalList("textures", "item/", VANILLA_TEXTURES::add); + loadInternalList("textures", "font/", VANILLA_TEXTURES::add); + for (String trimItem : TRIM_ITEMS) { + for (String trimColorPalette : TRIM_COLOR_PALETTES) { + VANILLA_TEXTURES.add(Key.of("minecraft", "trims/items/" + trimItem + "_" + trimColorPalette)); + } + } + + loadInternalList("models", "block/", VANILLA_MODELS::add); + loadInternalList("models", "item/", VANILLA_MODELS::add); + VANILLA_MODELS.add(Key.of("minecraft", "builtin/entity")); + for (int i = 0; i < 256; i++) { + VANILLA_TEXTURES.add(Key.of("minecraft", "font/unicode_page_" + String.format("%02x", i))); + } } private void loadInternalData(String path, BiConsumer callback) { @@ -122,19 +137,25 @@ public abstract class AbstractPackManager implements PackManager { } } - private void loadInternalList(String path, Consumer callback) { - try (InputStream inputStream = this.plugin.resourceStream(path)) { + private void loadInternalList(String type, String prefix, Consumer callback) { + try (InputStream inputStream = this.plugin.resourceStream("internal/" + type + "/" + prefix + "_list.json")) { if (inputStream != null) { JsonObject listJson = JsonParser.parseReader(new InputStreamReader(inputStream)).getAsJsonObject(); - JsonArray list = listJson.getAsJsonArray("files"); - for (JsonElement element : list) { + JsonArray fileList = listJson.getAsJsonArray("files"); + for (JsonElement element : fileList) { if (element instanceof JsonPrimitive primitive) { - callback.accept(Key.of(FileUtils.pathWithoutExtension(primitive.getAsString()))); + callback.accept(Key.of(prefix + FileUtils.pathWithoutExtension(primitive.getAsString()))); + } + } + JsonArray directoryList = listJson.getAsJsonArray("directories"); + for (JsonElement element : directoryList) { + if (element instanceof JsonPrimitive primitive) { + loadInternalList(type, prefix + primitive.getAsString() + "/", callback); } } } } catch (IOException e) { - this.plugin.logger().warn("Failed to load " + path, e); + this.plugin.logger().warn("Failed to load internal _list.json" + prefix, e); } } @@ -266,7 +287,7 @@ public abstract class AbstractPackManager implements PackManager { String author = null; boolean enable = true; if (Files.exists(metaFile) && Files.isRegularFile(metaFile)) { - YamlDocument metaYML = Config.instance().loadYamlData(metaFile.toFile()); + YamlDocument metaYML = Config.instance().loadYamlData(metaFile); enable = metaYML.getBoolean("enable", true); namespace = metaYML.getString("namespace", namespace); description = metaYML.getString("description"); @@ -439,7 +460,6 @@ public abstract class AbstractPackManager implements PackManager { TreeMap> cachedConfigs = new TreeMap<>(); Map previousFiles = this.cachedConfigFiles; this.cachedConfigFiles = new Object2ObjectOpenHashMap<>(32); - Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); for (Pack pack : loadedPacks()) { if (!pack.enabled()) continue; Path configurationFolderPath = pack.configurationFolder(); @@ -456,6 +476,7 @@ public abstract class AbstractPackManager implements PackManager { AbstractPackManager.this.cachedConfigFiles.put(path, cachedFile); } else { try (InputStreamReader inputStream = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { + Yaml yaml = new Yaml(new StringKeyConstructor(path, new LoaderOptions())); Map data = yaml.load(inputStream); if (data == null) return FileVisitResult.CONTINUE; cachedFile = new CachedConfigFile(data, pack, lastModifiedTime, size); @@ -463,11 +484,16 @@ public abstract class AbstractPackManager implements PackManager { } catch (IOException e) { AbstractPackManager.this.plugin.logger().severe("Error while reading config file: " + path, e); return FileVisitResult.CONTINUE; + } catch (LocalizedException e) { + e.setArgument(0, path.toString()); + TranslationManager.instance().log(e.node(), e.arguments()); + return FileVisitResult.CONTINUE; } } for (Map.Entry entry : cachedFile.config().entrySet()) { processConfigEntry(entry, path, cachedFile.pack(), (p, c) -> - cachedConfigs.computeIfAbsent(p, k -> new ArrayList<>()).add(c)); + cachedConfigs.computeIfAbsent(p, k -> new ArrayList<>()).add(c) + ); } } return FileVisitResult.CONTINUE; @@ -487,6 +513,7 @@ public abstract class AbstractPackManager implements PackManager { this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); for (Map.Entry> entry : cachedConfigs.entrySet()) { ConfigParser parser = entry.getKey(); + if (!predicate.test(parser)) continue; long t1 = System.nanoTime(); for (CachedConfigSection cached : entry.getValue()) { for (Map.Entry configEntry : cached.config().entrySet()) { @@ -494,12 +521,13 @@ public abstract class AbstractPackManager implements PackManager { Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); try { if (parser.supportsParsingObject()) { + // do not apply templates parser.parseObject(cached.pack(), cached.filePath(), id, configEntry.getValue()); - } else if (predicate.test(parser)) { + } else { if (configEntry.getValue() instanceof Map configSection0) { - Map configSection1 = castToMap(configSection0, false); - if ((boolean) configSection1.getOrDefault("enable", true)) { - parser.parseSection(cached.pack(), cached.filePath(), id, plugin.templateManager().applyTemplates(id, configSection1)); + Map config = castToMap(configSection0, false); + if ((boolean) config.getOrDefault("enable", true)) { + parser.parseSection(cached.pack(), cached.filePath(), id, MiscUtils.castToMap(this.plugin.templateManager().applyTemplates(id, config), false)); } } else { TranslationManager.instance().log("warning.config.structure.not_section", cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName()); @@ -513,7 +541,7 @@ public abstract class AbstractPackManager implements PackManager { TranslationManager.instance().log(e.node(), e.arguments()); this.plugin.debug(e::node); } catch (Exception e) { - this.plugin.logger().warn("Unexpected error loading file " + cached.filePath() + " - '" + parser.sectionId()[0] + "." + key + "'. Please find the cause according to the stacktrace or seek developer help.", e); + this.plugin.logger().warn("Unexpected error loading file " + cached.filePath() + " - '" + parser.sectionId()[0] + "." + key + "'. Please find the cause according to the stacktrace or seek developer help. Additional info: " + GsonHelper.get().toJson(configEntry.getValue()), e); } } } @@ -572,6 +600,9 @@ public abstract class AbstractPackManager implements PackManager { this.generateClientLang(generatedPackPath); this.generateEquipments(generatedPackPath); this.generateParticle(generatedPackPath); + if (Config.validateResourcePack()) { + this.validateResourcePack(generatedPackPath); + } Path finalPath = resourcePackPath(); Files.createDirectories(finalPath.getParent()); try { @@ -585,6 +616,234 @@ public abstract class AbstractPackManager implements PackManager { } } + @SuppressWarnings("DuplicatedCode") + private void validateResourcePack(Path path) throws IOException { + List rootPaths = FileUtils.collectOverlays(path); + + Multimap imageToFonts = ArrayListMultimap.create(); // 图片到字体的映射 + Multimap modelToItems = ArrayListMultimap.create(); // 模型到物品的映射 + Multimap modelToBlocks = ArrayListMultimap.create(); // 模型到方块的映射 + Multimap imageToModels = ArrayListMultimap.create(); // 图片到模型的映射 + + for (Path rootPath : rootPaths) { + Path assetsPath = rootPath.resolve("assets"); + if (!Files.isDirectory(assetsPath)) continue; + + for (Path namespacePath : FileUtils.collectNamespaces(assetsPath)) { + Path fontPath = namespacePath.resolve("font"); + if (Files.isDirectory(fontPath)) { + Files.walkFileTree(fontPath, new SimpleFileVisitor<>() { + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { + if (!isJsonFile(file)) return FileVisitResult.CONTINUE; + JsonObject fontJson = GsonHelper.readJsonFile(file).getAsJsonObject(); + JsonArray providers = fontJson.getAsJsonArray("providers"); + if (providers != null) { + Key fontName = Key.of(namespacePath.getFileName().toString(), FileUtils.pathWithoutExtension(file.getFileName().toString())); + for (JsonElement provider : providers) { + if (provider instanceof JsonObject providerJO && providerJO.has("type")) { + String type = providerJO.get("type").getAsString(); + if (type.equals("bitmap") && providerJO.has("file")) { + String pngFile = providerJO.get("file").getAsString(); + Key resourceLocation = Key.of(FileUtils.pathWithoutExtension(pngFile)); + imageToFonts.put(resourceLocation, fontName); + } + } + } + } + return FileVisitResult.CONTINUE; + } + }); + } + + Path itemsPath = namespacePath.resolve("items"); + if (Files.isDirectory(itemsPath)) { + Files.walkFileTree(itemsPath, new SimpleFileVisitor<>() { + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { + if (!isJsonFile(file)) return FileVisitResult.CONTINUE; + JsonObject itemJson = GsonHelper.readJsonFile(file).getAsJsonObject(); + Key item = Key.of(namespacePath.getFileName().toString(), FileUtils.pathWithoutExtension(file.getFileName().toString())); + collectItemModelsDeeply(itemJson, (resourceLocation) -> modelToItems.put(resourceLocation, item)); + return FileVisitResult.CONTINUE; + } + }); + } + + Path blockStatesPath = namespacePath.resolve("blockstates"); + if (Files.isDirectory(blockStatesPath)) { + Files.walkFileTree(blockStatesPath, new SimpleFileVisitor<>() { + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path file, @NotNull BasicFileAttributes attrs) throws IOException { + if (!isJsonFile(file)) return FileVisitResult.CONTINUE; + String blockId = FileUtils.pathWithoutExtension(file.getFileName().toString()); + JsonObject blockStateJson = GsonHelper.readJsonFile(file).getAsJsonObject(); + if (blockStateJson.has("multipart")) { + collectMultipart(blockStateJson.getAsJsonArray("multipart"), (location) -> modelToBlocks.put(location, blockId)); + } else if (blockStateJson.has("variants")) { + collectVariants(blockId, blockStateJson.getAsJsonObject("variants"), modelToBlocks::put); + } + return FileVisitResult.CONTINUE; + } + }); + } + } + } + + label: for (Map.Entry> entry : imageToFonts.asMap().entrySet()) { + Key key = entry.getKey(); + if (VANILLA_TEXTURES.contains(key)) continue; + String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; + for (Path rootPath : rootPaths) { + if (Files.exists(rootPath.resolve(imagePath))) { + continue label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_font_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); + } + + label: for (Map.Entry> entry : modelToItems.asMap().entrySet()) { + Key key = entry.getKey(); + String modelPath = "assets/" + key.namespace() + "/models/" + key.value() + ".json"; + if (VANILLA_MODELS.contains(key)) continue; + for (Path rootPath : rootPaths) { + Path modelJsonPath = rootPath.resolve(modelPath); + if (Files.exists(rootPath.resolve(modelPath))) { + collectModels(key, GsonHelper.readJsonFile(modelJsonPath).getAsJsonObject(), rootPaths, imageToModels); + continue label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_item_model", entry.getValue().stream().distinct().toList().toString(), modelPath); + } + + label: for (Map.Entry> entry : modelToBlocks.asMap().entrySet()) { + Key key = entry.getKey(); + String modelPath = "assets/" + key.namespace() + "/models/" + key.value() + ".json"; + if (VANILLA_MODELS.contains(key)) continue; + for (Path rootPath : rootPaths) { + Path modelJsonPath = rootPath.resolve(modelPath); + if (Files.exists(modelJsonPath)) { + collectModels(key, GsonHelper.readJsonFile(modelJsonPath).getAsJsonObject(), rootPaths, imageToModels); + continue label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_block_model", entry.getValue().stream().distinct().toList().toString(), modelPath); + } + + label: for (Map.Entry> entry : imageToModels.asMap().entrySet()) { + Key key = entry.getKey(); + if (VANILLA_TEXTURES.contains(key)) continue; + String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; + for (Path rootPath : rootPaths) { + if (Files.exists(rootPath.resolve(imagePath))) { + continue label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_model_texture", entry.getValue().stream().distinct().toList().toString(), imagePath); + } + } + + private static void collectModels(Key model, JsonObject modelJson, List rootPaths, Multimap imageToModels) throws IOException { + if (modelJson.has("parent")) { + Key parentResourceLocation = Key.from(modelJson.get("parent").getAsString()); + if (!VANILLA_MODELS.contains(parentResourceLocation)) { + String parentModelPath = "assets/" + parentResourceLocation.namespace() + "/models/" + parentResourceLocation.value() + ".json"; + label: { + for (Path rootPath : rootPaths) { + Path modelJsonPath = rootPath.resolve(parentModelPath); + if (Files.exists(modelJsonPath)) { + collectModels(parentResourceLocation, GsonHelper.readJsonFile(modelJsonPath).getAsJsonObject(), rootPaths, imageToModels); + break label; + } + } + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_parent_model", model.asString(), parentModelPath); + } + } + } + if (modelJson.has("textures")) { + JsonObject textures = modelJson.get("textures").getAsJsonObject(); + for (Map.Entry entry : textures.entrySet()) { + String value = entry.getValue().getAsString(); + if (value.charAt(0) == '#') continue; + Key textureResourceLocation = Key.from(value); + imageToModels.put(textureResourceLocation, model); + } + } + } + + private static void collectMultipart(JsonArray jsonArray, Consumer callback) { + for (JsonElement element : jsonArray) { + if (element instanceof JsonObject jo) { + JsonElement applyJE = jo.get("apply"); + if (applyJE instanceof JsonObject applyJO) { + String modelPath = applyJO.get("model").getAsString(); + Key location = Key.from(modelPath); + callback.accept(location); + } else if (applyJE instanceof JsonArray applyJA) { + for (JsonElement applyInnerJE : applyJA) { + if (applyInnerJE instanceof JsonObject applyInnerJO) { + String modelPath = applyInnerJO.get("model").getAsString(); + Key location = Key.from(modelPath); + callback.accept(location); + } + } + } + } + } + } + + private static void collectVariants(String block, JsonObject jsonObject, BiConsumer callback) { + for (Map.Entry entry : jsonObject.entrySet()) { + if (entry.getValue() instanceof JsonObject entryJO) { + String modelPath = entryJO.get("model").getAsString(); + Key location = Key.from(modelPath); + callback.accept(location, block + "[" + entry.getKey() + "]"); + } else if (entry.getValue() instanceof JsonArray entryJA) { + for (JsonElement entryInnerJE : entryJA) { + if (entryInnerJE instanceof JsonObject entryJO) { + String modelPath = entryJO.get("model").getAsString(); + Key location = Key.from(modelPath); + callback.accept(location, block + "[" + entry.getKey() + "]"); + } + } + } + } + } + + private static boolean isJsonFile(Path filePath) { + String fileName = filePath.getFileName().toString(); + return fileName.endsWith(".json") || fileName.endsWith(".mcmeta"); + } + + private static void collectItemModelsDeeply(JsonObject jo, Consumer callback) { + JsonElement modelJE = jo.get("model"); + if (modelJE instanceof JsonPrimitive jsonPrimitive) { + Key location = Key.from(jsonPrimitive.getAsString()); + callback.accept(location); + return; + } + if (jo.has("type") && jo.has("base")) { + if (jo.get("type") instanceof JsonPrimitive jp1 && jo.get("base") instanceof JsonPrimitive jp2) { + String type = jp1.getAsString(); + if (type.equals("minecraft:special") || type.equals("special")) { + Key location = Key.from(jp2.getAsString()); + callback.accept(location); + } + } + } + for (Map.Entry entry : jo.entrySet()) { + if (entry.getValue() instanceof JsonObject innerJO) { + collectItemModelsDeeply(innerJO, callback); + } else if (entry.getValue() instanceof JsonArray innerJA) { + for (JsonElement innerElement : innerJA) { + if (innerElement instanceof JsonObject innerJO) { + collectItemModelsDeeply(innerJO, callback); + } + } + } + } + } + private void generateParticle(Path generatedPackPath) { if (!Config.removeTintedLeavesParticle()) return; if (Config.packMaxVersion() < 21.49f) return; @@ -835,8 +1094,8 @@ public abstract class AbstractPackManager implements PackManager { } private void generateBlockOverrides(Path generatedPackPath) { - File blockStatesFile = new File(plugin.dataFolderFile(), "blockstates.yml"); - if (!blockStatesFile.exists()) plugin.saveResource("blockstates.yml"); + Path blockStatesFile = this.plugin.dataFolderPath().resolve("blockstates.yml"); + if (!Files.exists(blockStatesFile)) this.plugin.saveResource("blockstates.yml"); YamlDocument preset = Config.instance().loadYamlData(blockStatesFile); for (Map.Entry> entry : plugin.blockManager().blockOverrides().entrySet()) { Key key = entry.getKey(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index 1706684c2..c320f80df 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -253,7 +253,6 @@ public class SelfHostHttpServer { @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - CraftEngine.instance().logger().warn("Channel error", cause); ctx.close(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/misc/EquipmentGeneration.java b/core/src/main/java/net/momirealms/craftengine/core/pack/misc/EquipmentGeneration.java index d3622cb72..47430f516 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/misc/EquipmentGeneration.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/misc/EquipmentGeneration.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.pack.misc; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import net.momirealms.craftengine.core.item.EquipmentData; +import net.momirealms.craftengine.core.item.setting.EquipmentData; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 39ede4ecb..04c267afc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -43,7 +43,6 @@ import java.util.function.Consumer; import java.util.function.Supplier; public abstract class CraftEngine implements Plugin { - public static final String MOD_CLASS = "net.momirealms.craftengine.mod.CraftEnginePlugin"; private static CraftEngine instance; protected PluginLogger logger; protected Consumer> debugger = (s) -> {}; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java index 3c48cfb5e..09b32b9a5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Platform.java @@ -3,4 +3,6 @@ package net.momirealms.craftengine.core.plugin; public interface Platform { void dispatchCommand(String command); + + Object nbt2Java(String nbt); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index e33d35e57..835b8f486 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -22,18 +22,13 @@ import net.momirealms.craftengine.core.plugin.logger.filter.DisconnectLogFilter; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.world.InjectionTarget; import net.momirealms.craftengine.core.world.chunk.storage.CompressionMethod; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.stream.Collectors; @@ -43,6 +38,8 @@ public class Config { private final Path configFilePath; private final String configVersion; private YamlDocument config; + private long lastModified; + private long size; protected boolean firstTime = true; protected boolean debug; @@ -62,6 +59,8 @@ public class Config { protected boolean resource_pack$protection$crash_tools$method_2; protected boolean resource_pack$protection$crash_tools$method_3; + protected boolean resource_pack$validate$enable; + protected boolean resource_pack$protection$obfuscation$enable; protected long resource_pack$protection$obfuscation$seed; protected boolean resource_pack$protection$obfuscation$fake_directory; @@ -90,7 +89,8 @@ public class Config { protected Path resource_pack$delivery$file_to_upload; protected Component resource_pack$send$prompt; - protected int performance$max_block_chain_update_limit; + protected int performance$max_note_block_chain_update_limit; + protected int performance$max_tripwire_chain_update_limit; protected int performance$max_emojis_per_parse; protected boolean light_system$force_update_light; @@ -155,48 +155,63 @@ public class Config { } public void load() { - if (Files.exists(this.configFilePath)) { - this.config = this.loadYamlData(this.configFilePath.toFile()); - String configVersion = config.getString("config-version"); - if (configVersion.equals(this.configVersion)) { - loadSettings(); - return; - } + // 文件不存在,则保存 + if (!Files.exists(this.configFilePath)) { + this.plugin.saveResource("config.yml"); + } + try { + BasicFileAttributes attributes = Files.readAttributes(this.configFilePath, BasicFileAttributes.class); + long lastModified = attributes.lastModifiedTime().toMillis(); + long size = attributes.size(); + if (lastModified != this.lastModified || size != this.size || this.config == null) { + byte[] configFileBytes = Files.readAllBytes(this.configFilePath); + try (InputStream inputStream = new ByteArrayInputStream(configFileBytes)) { + this.config = YamlDocument.create(inputStream); + String configVersion = this.config.getString("config-version"); + if (!configVersion.equals(this.configVersion)) { + this.updateConfigVersion(configFileBytes); + } + } + // 加载配置文件 + this.loadSettings(); + this.lastModified = lastModified; + this.size = size; + } + } catch (IOException e) { + this.plugin.logger().severe("Failed to load config.yml", e); } - this.updateConfigVersion(); - loadSettings(); } - private void updateConfigVersion() { - this.config = this.loadYamlConfig( - "config.yml", - GeneralSettings.builder() - .setRouteSeparator('.') - .setUseDefaults(false) - .build(), - LoaderSettings - .builder() - .setAutoUpdate(true) - .build(), - DumperSettings.builder() - .setEscapeUnprintable(false) - .setScalarFormatter((tag, value, role, def) -> { - if (role == NodeRole.KEY) { - return ScalarStyle.PLAIN; - } else { - return tag == Tag.STR ? ScalarStyle.DOUBLE_QUOTED : ScalarStyle.PLAIN; - } - }) - .build(), - UpdaterSettings - .builder() - .setVersioning(new BasicVersioning("config-version")) - .build() - ); + private void updateConfigVersion(byte[] bytes) throws IOException { + try (InputStream inputStream = new ByteArrayInputStream(bytes)) { + this.config = YamlDocument.create(inputStream, this.plugin.resourceStream("config.yml"), GeneralSettings.builder() + .setRouteSeparator('.') + .setUseDefaults(false) + .build(), + LoaderSettings + .builder() + .setAutoUpdate(true) + .build(), + DumperSettings.builder() + .setEscapeUnprintable(false) + .setScalarFormatter((tag, value, role, def) -> { + if (role == NodeRole.KEY) { + return ScalarStyle.PLAIN; + } else { + return tag == Tag.STR ? ScalarStyle.DOUBLE_QUOTED : ScalarStyle.PLAIN; + } + }) + .build(), + UpdaterSettings + .builder() + .setVersioning(new BasicVersioning("config-version")) + .addIgnoredRoute(PluginProperties.getValue("config"), "resource-pack.delivery.hosting", '.') + .build()); + } try { - config.save(new File(plugin.dataFolderFile(), "config.yml")); + this.config.save(new File(plugin.dataFolderFile(), "config.yml")); } catch (IOException e) { - throw new RuntimeException(e); + this.plugin.logger().warn("Could not save config.yml", e); } } @@ -246,6 +261,7 @@ public class Config { resource_pack$protection$obfuscation$resource_location$bypass_models = config.getStringList("resource-pack.protection.obfuscation.resource-location.bypass-models"); resource_pack$protection$obfuscation$resource_location$bypass_sounds = config.getStringList("resource-pack.protection.obfuscation.resource-location.bypass-sounds"); resource_pack$protection$obfuscation$resource_location$bypass_equipments = config.getStringList("resource-pack.protection.obfuscation.resource-location.bypass-equipments"); + resource_pack$validate$enable = config.getBoolean("resource-pack.validate.enable", true); try { resource_pack$duplicated_files_handler = config.getMapList("resource-pack.duplicated-files-handler").stream().map(it -> { @@ -264,7 +280,8 @@ public class Config { item$non_italic_tag = config.getBoolean("item.non-italic-tag", false); // performance - performance$max_block_chain_update_limit = config.getInt("performance.max-block-chain-update-limit", 64); + performance$max_note_block_chain_update_limit = config.getInt("performance.max-note-block-chain-update-limit", 64); + performance$max_tripwire_chain_update_limit = config.getInt("performance.max-tripwire-chain-update-limit", 128); performance$max_emojis_per_parse = config.getInt("performance.max-emojis-per-parse", 32); // light @@ -341,17 +358,6 @@ public class Config { emoji$book = config.getBoolean("emoji.book", true); emoji$sign = config.getBoolean("emoji.sign", true); - Class modClazz = ReflectionUtils.getClazz(CraftEngine.MOD_CLASS); - if (modClazz != null) { - Method setMaxChainMethod = ReflectionUtils.getStaticMethod(modClazz, void.class, new String[] {"setMaxChainUpdate"}, int.class); - try { - assert setMaxChainMethod != null; - setMaxChainMethod.invoke(null, performance$max_block_chain_update_limit); - } catch (IllegalAccessException | InvocationTargetException e) { - plugin.logger().warn("Failed to set max chain update", e); - } - } - firstTime = false; } @@ -390,8 +396,8 @@ public class Config { return instance.resource_pack$override_uniform_font; } - public static int maxChainUpdate() { - return instance.performance$max_block_chain_update_limit; + public static int maxNoteBlockChainUpdate() { + return instance.performance$max_note_block_chain_update_limit; } public static int maxEmojisPerParse() { @@ -726,12 +732,16 @@ public class Config { return instance.chunk_system$injection$target; } + public static boolean validateResourcePack() { + return instance.resource_pack$validate$enable; + } + public YamlDocument loadOrCreateYamlData(String fileName) { - File file = new File(this.plugin.dataFolderFile(), fileName); - if (!file.exists()) { + Path path = this.plugin.dataFolderPath().resolve(fileName); + if (!Files.exists(path)) { this.plugin.saveResource(fileName); } - return this.loadYamlData(file); + return this.loadYamlData(path); } public YamlDocument loadYamlConfig(String filePath, GeneralSettings generalSettings, LoaderSettings loaderSettings, DumperSettings dumperSettings, UpdaterSettings updaterSettings) { @@ -743,8 +753,8 @@ public class Config { } } - public YamlDocument loadYamlData(File file) { - try (InputStream inputStream = new FileInputStream(file)) { + public YamlDocument loadYamlData(Path file) { + try (InputStream inputStream = Files.newInputStream(file)) { return YamlDocument.create(inputStream); } catch (IOException e) { this.plugin.logger().severe("Failed to load config " + file, e); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/StringKeyConstructor.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/StringKeyConstructor.java index 8db8ae617..3551122d0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/StringKeyConstructor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/StringKeyConstructor.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.plugin.config; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.nodes.MappingNode; @@ -7,13 +8,16 @@ import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.NodeTuple; import org.yaml.snakeyaml.nodes.ScalarNode; +import java.nio.file.Path; import java.util.LinkedHashMap; import java.util.Map; public class StringKeyConstructor extends SafeConstructor { + private final Path path; - public StringKeyConstructor(LoaderOptions loaderOptions) { + public StringKeyConstructor(Path path, LoaderOptions loaderOptions) { super(loaderOptions); + this.path = path; } @Override @@ -24,7 +28,10 @@ public class StringKeyConstructor extends SafeConstructor { Node valueNode = tuple.getValueNode(); String key = constructScalar((ScalarNode) keyNode); Object value = constructObject(valueNode); - map.put(key, value); + Object previous = map.put(key, value); + if (previous != null) { + TranslationManager.instance().log("warning.config.yaml.duplicated_key", this.path.toAbsolutePath().toString(), key, String.valueOf(node.getStartMark().getLine() + 1)); + } } return map; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/TranslationConfigConstructor.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/TranslationConfigConstructor.java new file mode 100644 index 000000000..d44abd0af --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/TranslationConfigConstructor.java @@ -0,0 +1,41 @@ +package net.momirealms.craftengine.core.plugin.config; + +import org.yaml.snakeyaml.LoaderOptions; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.nodes.MappingNode; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.NodeTuple; +import org.yaml.snakeyaml.nodes.ScalarNode; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.StringJoiner; + +public class TranslationConfigConstructor extends SafeConstructor { + + public TranslationConfigConstructor(LoaderOptions loaderOptions) { + super(loaderOptions); + } + + @Override + protected Map constructMapping(MappingNode node) { + Map map = new LinkedHashMap<>(); + for (NodeTuple tuple : node.getValue()) { + Node keyNode = tuple.getKeyNode(); + Node valueNode = tuple.getValueNode(); + String key = constructScalar((ScalarNode) keyNode); + Object value = constructObject(valueNode); + if (value instanceof List list) { + StringJoiner stringJoiner = new StringJoiner(""); + for (Object str : list) { + stringJoiner.add(String.valueOf(str)); + } + map.put(key, stringJoiner.toString()); + } else { + map.put(key, value.toString()); + } + } + return map; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ExpressionTemplateArgument.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ExpressionTemplateArgument.java new file mode 100644 index 000000000..a92d6fdf2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ExpressionTemplateArgument.java @@ -0,0 +1,66 @@ +package net.momirealms.craftengine.core.plugin.config.template; + +import com.ezylang.evalex.Expression; +import com.ezylang.evalex.data.EvaluationValue; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class ExpressionTemplateArgument implements TemplateArgument { + public static final Factory FACTORY = new Factory(); + private final TemplateManager.ArgumentString expression; + private final ValueType valueType; + + protected ExpressionTemplateArgument(String expression, ValueType valueType) { + this.expression = TemplateManager.preParse(expression); + this.valueType = valueType; + } + + @Override + public Object get(Map arguments) { + String expression = Optional.ofNullable(this.expression.get(arguments)).map(String::valueOf).orElse(null); + if (expression == null) return null; + try { + return this.valueType.formatter().apply(new Expression(expression).evaluate()); + } catch (Exception e) { + throw new RuntimeException("Failed to process expression argument: " + this.expression, e); + } + } + + @Override + public Key type() { + return TemplateArguments.EXPRESSION; + } + + protected enum ValueType { + INT(e -> e.getNumberValue().intValue()), + LONG(e -> e.getNumberValue().longValue()), + SHORT(e -> e.getNumberValue().shortValueExact()), + DOUBLE(e -> e.getNumberValue().doubleValue()), + FLOAT(e -> e.getNumberValue().floatValue()), + BOOLEAN(EvaluationValue::getBooleanValue),; + + private final Function formatter; + + ValueType(Function formatter) { + this.formatter = formatter; + } + + public Function formatter() { + return this.formatter; + } + } + + public static class Factory implements TemplateArgumentFactory { + @Override + public TemplateArgument create(Map arguments) { + return new ExpressionTemplateArgument( + arguments.getOrDefault("expression", "").toString(), + ValueType.valueOf(arguments.getOrDefault("value-type", "double").toString().toUpperCase(Locale.ENGLISH)) + ); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ListTemplateArgument.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ListTemplateArgument.java index 0ed041519..eae376ac0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ListTemplateArgument.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ListTemplateArgument.java @@ -16,7 +16,7 @@ public class ListTemplateArgument implements TemplateArgument { } @Override - public List get() { + public List get(Map arguments) { return value; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/MapTemplateArgument.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/MapTemplateArgument.java index c037578fb..9df939320 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/MapTemplateArgument.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/MapTemplateArgument.java @@ -14,7 +14,7 @@ public class MapTemplateArgument implements TemplateArgument { } @Override - public Map get() { + public Map get(Map arguments) { return value; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/NullTemplateArgument.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/NullTemplateArgument.java index fed348953..8a568d2af 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/NullTemplateArgument.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/NullTemplateArgument.java @@ -17,7 +17,7 @@ public class NullTemplateArgument implements TemplateArgument { } @Override - public Object get() { + public Object get(Map arguments) { return null; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ObjectTemplateArgument.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ObjectTemplateArgument.java index 51e6b07e0..e78af6b66 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ObjectTemplateArgument.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ObjectTemplateArgument.java @@ -2,6 +2,8 @@ package net.momirealms.craftengine.core.plugin.config.template; import net.momirealms.craftengine.core.util.Key; +import java.util.Map; + public class ObjectTemplateArgument implements TemplateArgument { private final Object value; @@ -9,13 +11,17 @@ public class ObjectTemplateArgument implements TemplateArgument { this.value = value; } + public static ObjectTemplateArgument of(Object value) { + return new ObjectTemplateArgument(value); + } + @Override public Key type() { return TemplateArguments.OBJECT; } @Override - public Object get() { + public Object get(Map arguments) { return this.value; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/PlainStringTemplateArgument.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/PlainStringTemplateArgument.java index a8017fcf5..a9ef8d6ae 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/PlainStringTemplateArgument.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/PlainStringTemplateArgument.java @@ -17,7 +17,7 @@ public class PlainStringTemplateArgument implements TemplateArgument { } @Override - public String get() { + public String get(Map arguments) { return value; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/SelfIncreaseIntTemplateArgument.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/SelfIncreaseIntTemplateArgument.java index d99690814..d01b87124 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/SelfIncreaseIntTemplateArgument.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/SelfIncreaseIntTemplateArgument.java @@ -19,9 +19,9 @@ public class SelfIncreaseIntTemplateArgument implements TemplateArgument { } @Override - public String get() { - String value = String.valueOf(current); - if (current < max) current += 1; + public String get(Map arguments) { + String value = String.valueOf(this.current); + if (this.current < this.max) this.current += 1; return value; } @@ -31,15 +31,15 @@ public class SelfIncreaseIntTemplateArgument implements TemplateArgument { } public int current() { - return current; + return this.current; } public int min() { - return min; + return this.min; } public int max() { - return max; + return this.max; } public static class Factory implements TemplateArgumentFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArgument.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArgument.java index 87181291d..9816cfebc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArgument.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArgument.java @@ -2,9 +2,11 @@ package net.momirealms.craftengine.core.plugin.config.template; import net.momirealms.craftengine.core.util.Key; -import java.util.function.Supplier; +import java.util.Map; -public interface TemplateArgument extends Supplier { +public interface TemplateArgument { Key type(); + + Object get(Map arguments); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArguments.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArguments.java index f437a7493..0586843f5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArguments.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateArguments.java @@ -15,6 +15,7 @@ public class TemplateArguments { public static final Key MAP = Key.of("craftengine:map"); public static final Key LIST = Key.of("craftengine:list"); public static final Key NULL = Key.of("craftengine:null"); + public static final Key EXPRESSION = Key.of("craftengine:expression"); public static final Key OBJECT = Key.of("craftengine:object"); // No Factory, internal use public static void register(Key key, TemplateArgumentFactory factory) { @@ -29,6 +30,7 @@ public class TemplateArguments { register(MAP, MapTemplateArgument.FACTORY); register(LIST, ListTemplateArgument.FACTORY); register(NULL, NullTemplateArgument.FACTORY); + register(EXPRESSION, ExpressionTemplateArgument.FACTORY); } public static TemplateArgument fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java index 4cf87fed6..0f7e64dd4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManager.java @@ -1,21 +1,304 @@ package net.momirealms.craftengine.core.plugin.config.template; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; +import java.util.ArrayList; +import java.util.List; import java.util.Map; -import java.util.regex.Pattern; public interface TemplateManager extends Manageable { - Pattern ARGUMENT_PATTERN = Pattern.compile("\\{[^{}]+}"); - String LEFT_BRACKET = "{"; - String RIGHT_BRACKET = "}"; - String TEMPLATE = "template"; - String OVERRIDES = "overrides"; - String ARGUMENTS = "arguments"; ConfigParser parser(); - Map applyTemplates(Key id, Map input); + Object applyTemplates(Key id, Object input); + + interface ArgumentString { + + String rawValue(); + + Object get(Map arguments); + } + + final class Literal implements ArgumentString { + private final String value; + + public Literal(String value) { + this.value = value; + } + + public static Literal literal(String value) { + return new Literal(value); + } + + @Override + public String rawValue() { + return this.value; + } + + @Override + public Object get(Map arguments) { + return this.value; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Literal literal)) return false; + return this.value.equals(literal.value); + } + + @Override + public int hashCode() { + return this.value.hashCode(); + } + + @Override + public String toString() { + return "Literal(" + this.value + ")"; + } + } + + final class Placeholder implements ArgumentString { + private final String placeholder; + private final String rawText; + private final Object defaultValue; + + public Placeholder(String placeholderContent) { + this.rawText = "${" + placeholderContent + "}"; + int separatorIndex = placeholderContent.indexOf(":-"); + if (separatorIndex == -1) { + this.placeholder = placeholderContent; + this.defaultValue = this.rawText; + } else { + this.placeholder = placeholderContent.substring(0, separatorIndex); + String defaultValueString = placeholderContent.substring(separatorIndex + 2); + try { + this.defaultValue = CraftEngine.instance().platform().nbt2Java(defaultValueString); + } catch (LocalizedResourceConfigException e) { + e.appendTailArgument(this.placeholder); + throw e; + } + } + } + + public static Placeholder placeholder(String placeholder) { + return new Placeholder(placeholder); + } + + @Override + public Object get(Map arguments) { + TemplateArgument replacement = arguments.get(this.placeholder); + if (replacement != null) { + return replacement.get(arguments); + } + return this.defaultValue; + } + + @Override + public String rawValue() { + return this.rawText; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Placeholder that)) return false; + return this.placeholder.equals(that.placeholder); + } + + @Override + public int hashCode() { + return this.placeholder.hashCode(); + } + + @Override + public String toString() { + return "Placeholder(" + this.placeholder + ")"; + } + } + + final class Complex2 implements ArgumentString { + private final String rawText; + private final ArgumentString arg1; + private final ArgumentString arg2; + + public Complex2(String rawText, ArgumentString arg1, ArgumentString arg2) { + this.arg1 = arg1; + this.arg2 = arg2; + this.rawText = rawText; + } + + @Override + public Object get(Map arguments) { + Object arg1 = this.arg1.get(arguments); + Object arg2 = this.arg2.get(arguments); + if (arg1 == null && arg2 == null) return null; + if (arg1 == null) return String.valueOf(arg2); + if (arg2 == null) return String.valueOf(arg1); + return String.valueOf(arg1) + arg2; + } + + @Override + public String rawValue() { + return this.rawText; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Complex that)) return false; + return this.rawText.equals(that.rawText); + } + + @Override + public int hashCode() { + return this.rawText.hashCode(); + } + + @Override + public String toString() { + return "Complex2(" + this.rawText + ")"; + } + } + + final class Complex implements ArgumentString { + private final List parts; + private final String rawText; + + public Complex(String rawText, List parts) { + this.parts = parts; + this.rawText = rawText; + } + + @Override + public Object get(Map arguments) { + StringBuilder result = new StringBuilder(); + boolean hasValue = false; + for (ArgumentString part : this.parts) { + Object arg = part.get(arguments); + if (arg != null) { + result.append(arg); + hasValue = true; + } + } + if (!hasValue) return null; + return result.toString(); + } + + @Override + public String rawValue() { + return this.rawText; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Complex that)) return false; + return this.rawText.equals(that.rawText); + } + + @Override + public int hashCode() { + return this.rawText.hashCode(); + } + + @Override + public String toString() { + return "Complex(" + this.rawText + ")"; + } + } + + static ArgumentString preParse(String input) { + if (input == null || input.isEmpty()) { + return Literal.literal(""); + } + + List arguments = new ArrayList<>(); + StringBuilder currentLiteral = new StringBuilder(); + final int n = input.length(); + int i = 0; + + while (i < n) { + char c = input.charAt(i); + + // --- 1. 优先检测占位符触发器 --- + if (c == '$' && i + 1 < n && input.charAt(i + 1) == '{') { + + // a. 提交之前的普通文本 + if (!currentLiteral.isEmpty()) { + arguments.add(Literal.literal(currentLiteral.toString())); + currentLiteral.setLength(0); + } + + // b. 解析占位符内部,此处的逻辑拥有自己的转义规则 + int contentStartIndex = i + 2; + StringBuilder keyBuilder = new StringBuilder(); + int depth = 1; + int j = contentStartIndex; + boolean foundMatch = false; + + while (j < n) { + char innerChar = input.charAt(j); + + // --- 占位符内部的转义逻辑 --- + if (innerChar == '\\') { + if (j + 1 < n && (input.charAt(j + 1) == '{' || input.charAt(j + 1) == '}')) { + keyBuilder.append(input.charAt(j + 1)); + j += 2; + } else { + // 在占位符内部,一个无法识别的转义\依旧被当作普通\处理 + keyBuilder.append(innerChar); + j++; + } + } else if (innerChar == '{') { + depth++; + keyBuilder.append(innerChar); + j++; + } else if (innerChar == '}') { + depth--; + if (depth == 0) { // 找到匹配的闭合括号 + arguments.add(Placeholder.placeholder(keyBuilder.toString())); + i = j + 1; + foundMatch = true; + break; + } + keyBuilder.append(innerChar); + j++; + } else { + keyBuilder.append(innerChar); + j++; + } + } + + if (foundMatch) { + continue; + } else { + // 未找到闭合括号,将 '$' 视为普通字符 + currentLiteral.append(c); + i++; + } + } + // --- 2. 其次,只处理对触发器'$'的转义 --- + else if (c == '\\' && i + 1 < n && input.charAt(i + 1) == '$') { + currentLiteral.append('$'); // 直接添加 '$' + i += 2; // 跳过 '\' 和 '$' + } + // --- 3. 处理所有其他字符(包括独立的'\'和'{')为普通文本 --- + else { + currentLiteral.append(c); + i++; + } + } + + if (!currentLiteral.isEmpty()) { + arguments.add(Literal.literal(currentLiteral.toString())); + } + + return switch (arguments.size()) { + case 0 -> Literal.literal(""); + case 1 -> arguments.getFirst(); + case 2 -> new Complex2(input, arguments.get(0), arguments.get(1)); + default -> new Complex(input, arguments); + }; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java index 1141f6083..398af24f7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java @@ -4,26 +4,38 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import org.jetbrains.annotations.NotNull; import java.nio.file.Path; import java.util.*; -import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.regex.Matcher; +@SuppressWarnings("DuplicatedCode") public class TemplateManagerImpl implements TemplateManager { + private static final ArgumentString TEMPLATE = Literal.literal("template"); + private static final ArgumentString OVERRIDES = Literal.literal("overrides"); + private static final ArgumentString ARGUMENTS = Literal.literal("arguments"); + private static final ArgumentString MERGES = Literal.literal("merges"); + private final static Set NON_TEMPLATE_ARGUMENTS = new HashSet<>(Set.of(TEMPLATE, ARGUMENTS, OVERRIDES, MERGES)); + private final Map templates = new HashMap<>(); - private final static Set NON_TEMPLATE_KEY = new HashSet<>(Set.of(TEMPLATE, ARGUMENTS, OVERRIDES)); private final TemplateParser templateParser; public TemplateManagerImpl() { this.templateParser = new TemplateParser(); } + @Override + public void unload() { + this.templates.clear(); + } + + @Override + public ConfigParser parser() { + return this.templateParser; + } + public class TemplateParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"templates", "template"}; @@ -47,240 +59,274 @@ public class TemplateManagerImpl implements TemplateManager { if (templates.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.template.duplicate", path.toString(), id.toString()); } - templates.put(id, obj); + // 预处理会将 string类型的键或值解析为ArgumentString,以加速模板应用。所以处理后不可能存在String类型。 + templates.put(id, preprocessUnknownValue(obj)); } } @Override - public void unload() { - this.templates.clear(); + public Object applyTemplates(Key id, Object input) { + Object preprocessedInput = preprocessUnknownValue(input); + return processUnknownValue(preprocessedInput, Map.of( + "__NAMESPACE__", PlainStringTemplateArgument.plain(id.namespace()), + "__ID__", PlainStringTemplateArgument.plain(id.value()) + )); } - @Override - public ConfigParser parser() { - return this.templateParser; - } - - @Override - public Map applyTemplates(Key id, Map input) { - Objects.requireNonNull(input, "Input must not be null"); - Map result = new LinkedHashMap<>(); - processMap(input, Map.of("{__ID__}", PlainStringTemplateArgument.plain(id.value()), - "{__NAMESPACE__}", PlainStringTemplateArgument.plain(id.namespace())), (obj) -> { - // 当前位于根节点下,如果下一级就是模板,则应把模板结果与当前map合并 - // 如果模板结果不是map,则为非法值,因为不可能出现类似于下方的配置 - // items: - // test:invalid: 111 - if (obj instanceof Map mapResult) { - result.putAll(MiscUtils.castToMap(mapResult, false)); - } else { - throw new IllegalArgumentException("Invalid template used. Input: " + GsonHelper.get().toJson(input) + ". Template: " + GsonHelper.get().toJson(obj)); + private Object preprocessUnknownValue(Object value) { + switch (value) { + case Map map -> { + Map in = MiscUtils.castToMap(map, false); + Map out = new LinkedHashMap<>(map.size()); + for (Map.Entry entry : in.entrySet()) { + out.put(TemplateManager.preParse(entry.getKey()), preprocessUnknownValue(entry.getValue())); + } + return out; } - }); - return result; + case List list -> { + List objList = new ArrayList<>(list.size()); + for (Object o : list) { + objList.add(preprocessUnknownValue(o)); + } + return objList; + } + case String string -> { + return TemplateManager.preParse(string); + } + case null, default -> { + return value; + } + } } // 对于处理map,只有input是已知map,而返回值可能并不是 - private void processMap(Map input, - Map parentArguments, - // 只有当前为模板的时候,才会调用callback - Consumer processCallBack) { + private Object processMap(Map input, + Map arguments) { // 传入的input是否含有template,这种情况下,返回值有可能是非map if (input.containsKey(TEMPLATE)) { - TemplateProcessingResult processingResult = processTemplates(input, parentArguments); - List templates = processingResult.templates(); - // 你敢保证template里没有template吗? - List processedTemplates = new ArrayList<>(); - // 先递归处理后再合并 - for (Object template : templates) { - processUnknownTypeMember(template, processingResult.arguments(), processedTemplates::add); - } - if (processedTemplates.isEmpty()) { - return; - } - Object firstTemplate = processedTemplates.get(0); - // 对于map和list,应当对多模板合并 - if (firstTemplate instanceof Map) { - Map results = new LinkedHashMap<>(); - // 仅仅合并list - for (Object processedTemplate : processedTemplates) { - if (processedTemplate instanceof Map anotherMap) { - results.putAll(MiscUtils.castToMap(anotherMap, false)); + TemplateProcessingResult processingResult = processTemplates(input, arguments); + List processedTemplates = processingResult.templates(); + if (!processedTemplates.isEmpty()) { + // 先获取第一个模板的类型 + Object firstTemplate = processedTemplates.getFirst(); + // 如果是map,应当深度合并 + if (firstTemplate instanceof Map) { + Map results = new LinkedHashMap<>(); + for (Object processedTemplate : processedTemplates) { + if (processedTemplate instanceof Map map) { + MiscUtils.deepMergeMaps(results, MiscUtils.castToMap(map, false)); + } } - } - results.putAll(processingResult.overrides()); - processCallBack.accept(results); - } else if (firstTemplate instanceof List) { - List results = new ArrayList<>(); - // 仅仅合并list - for (Object processedTemplate : processedTemplates) { - if (processedTemplate instanceof List anotherList) { - results.addAll(anotherList); + if (processingResult.overrides() instanceof Map overrides) { + results.putAll(MiscUtils.castToMap(overrides, false)); } + if (processingResult.merges() instanceof Map merges) { + MiscUtils.deepMergeMaps(results, MiscUtils.castToMap(merges, false)); + } + return results; + } else if (firstTemplate instanceof List) { + List results = new ArrayList<>(); + // 仅仅合并list + for (Object processedTemplate : processedTemplates) { + if (processedTemplate instanceof List anotherList) { + results.addAll(anotherList); + } + } + if (processingResult.overrides() instanceof List overrides) { + results.clear(); + results.addAll(overrides); + } + if (processingResult.merges() instanceof List merges) { + results.addAll(merges); + } + return results; + } else { + // 有覆写用覆写,无覆写返回最后一个模板值 + if (processingResult.overrides() != null) { + return processingResult.overrides(); + } + if (processingResult.merges() != null) { + return processingResult.merges(); + } + return processedTemplates.getLast(); } - processCallBack.accept(results); } else { - // 其他情况下应当忽略其他的template - processCallBack.accept(firstTemplate); + // 模板为空啦,如果是map,则合并 + if (processingResult.overrides() instanceof Map overrides) { + Map output = new LinkedHashMap<>(MiscUtils.castToMap(overrides, false)); + if (processingResult.merges() instanceof Map merges) { + MiscUtils.deepMergeMaps(output, MiscUtils.castToMap(merges, false)); + } + return output; + } else if (processingResult.overrides() instanceof List overrides) { + List output = new ArrayList<>(overrides); + if (processingResult.merges() instanceof List merges) { + output.addAll(merges); + } + return output; + } + // 否则有overrides就返回overrides + if (processingResult.overrides() != null) { + return processingResult.overrides(); + } + // 否则有merges就返回merges + if (processingResult.merges() != null) { + return processingResult.merges(); + } + return null; } } else { // 如果不是模板,则返回值一定是map // 依次处理map下的每个参数 - Map result = new LinkedHashMap<>(); - for (Map.Entry inputEntry : input.entrySet()) { - processUnknownTypeMember(inputEntry.getValue(), parentArguments, (processed) -> result.put(inputEntry.getKey(), processed)); + Map result = new LinkedHashMap<>(input.size()); + for (Map.Entry inputEntry : input.entrySet()) { + Object key = inputEntry.getKey().get(arguments); + // 如果key为null说明不插入此键 + if (key != null) { + result.put(key.toString(), processUnknownValue(inputEntry.getValue(), arguments)); + } } - processCallBack.accept(result); + return result; } } - // 处理一个类型未知的值,本方法只管将member处理好后,传递回调用者 - private void processUnknownTypeMember(Object member, - Map parentArguments, - Consumer processCallback) { - if (member instanceof Map innerMap) { + // 处理一个类型未知的值,本方法只管将member处理好后,传递回调用者a + @SuppressWarnings("unchecked") + private Object processUnknownValue(Object value, + Map arguments) { + switch (value) { + case Map innerMap -> // map下面还是个map吗?这并不一定 - // 比如 - // a: - // template: xxx - // 这时候a并不一定是map,最终类型取决于template,那么应当根据template的结果进行调整,所以我们继续交给上方方法处理 - processMap(MiscUtils.castToMap(innerMap, false), parentArguments, processCallback); - } else if (member instanceof List innerList) { - // map 下面是个list,那么对下面的每个成员再次处理 - List result = new ArrayList<>(); - for (Object item : innerList) { - // 处理完以后,加入到list内 - processUnknownTypeMember(item, parentArguments, result::add); + // 这时候并不一定是map,最终类型取决于template,那么应当根据template的结果进行调整,所以我们继续交给上方方法处理 + { + return processMap((Map) innerMap, arguments); + } + case List innerList -> { + List result = new ArrayList<>(); + for (Object item : innerList) { + result.add(processUnknownValue(item, arguments)); + } + return result; + } + case ArgumentString arg -> { + return arg.get(arguments); + } + case null, default -> { + return value; } - processCallback.accept(result); - } else if (member instanceof String possibleArgument) { - // 如果是个string,其可能是 {xxx} 的参数,那么就尝试应用参数后再返回 - processCallback.accept(applyArgument(possibleArgument, parentArguments)); - } else { - // 对于其他值,直接处理 - processCallback.accept(member); } } - private TemplateProcessingResult processTemplates(Map input, + @SuppressWarnings("unchecked") + private TemplateProcessingResult processTemplates(Map input, Map parentArguments) { + int knownKeys = 1; // 先获取template节点下所有的模板 - List templateIds = MiscUtils.getAsStringList(input.get(TEMPLATE)); - List templateList = new ArrayList<>(); - for (String templateId : templateIds) { - // 如果模板id被用了参数,则应先应用参数后再查询模板 - Object actualTemplate = templateId.contains(LEFT_BRACKET) && templateId.contains(RIGHT_BRACKET) ? applyArgument(templateId, parentArguments) : templateId; - if (actualTemplate == null) continue; // 忽略被null掉的模板 - Object template = Optional.ofNullable(templates.get(Key.of(actualTemplate.toString()))) - .orElseThrow(() -> new IllegalArgumentException("Template not found: " + actualTemplate)); - templateList.add(template); - } + List templateIds = MiscUtils.getAsList(input.get(TEMPLATE), ArgumentString.class); + List templateList = new ArrayList<>(templateIds.size()); + + // 获取arguments + Object argument = input.get(ARGUMENTS); + boolean hasArgument = argument != null; + if (hasArgument) knownKeys++; + // 将本节点下的参数与父参数合并 - Map arguments = mergeArguments( - MiscUtils.castToMap(input.getOrDefault(ARGUMENTS, Collections.emptyMap()), false), + Map arguments = hasArgument ? mergeArguments( + (Map) argument, parentArguments - ); - // 对overrides参数应用 本节点 + 父节点 参数 - Map overrides = new LinkedHashMap<>(); - processMap(MiscUtils.castToMap(input.getOrDefault(OVERRIDES, Map.of()), false), arguments, (obj) -> { - // 如果overrides的下一级就是一个模板,则模板必须为map类型 - if (obj instanceof Map mapResult) { - overrides.putAll(MiscUtils.castToMap(mapResult, false)); - } else { - throw new IllegalArgumentException("Invalid template used. Input: " + GsonHelper.get().toJson(input) + ". Template: " + GsonHelper.get().toJson(obj)); - } - }); - // 会不会有一种可能,有笨比用户不会使用overrides,把模板和普通配置混合在了一起?再次遍历input后处理 - for (Map.Entry inputEntry : input.entrySet()) { - String inputKey = inputEntry.getKey(); - if (NON_TEMPLATE_KEY.contains(inputKey)) continue; - // 处理那些overrides - processUnknownTypeMember(inputEntry.getValue(), arguments, (processed) -> overrides.put(inputKey, processed)); + ) : parentArguments; + + // 获取处理后的template + for (ArgumentString templateId : templateIds) { + // 如果模板id被用了参数,则应先应用参数后再查询模板 + Object actualTemplate = templateId.get(parentArguments); + if (actualTemplate == null) continue; // 忽略被null掉的模板 + Object template = Optional.ofNullable(this.templates.get(Key.of(actualTemplate.toString()))) + .orElseThrow(() -> new LocalizedResourceConfigException("warning.config.template.invalid", actualTemplate.toString())); + Object processedTemplate = processUnknownValue(template, arguments); + if (processedTemplate != null) templateList.add(processedTemplate); + } + + // 获取overrides + Object override = input.get(OVERRIDES); + boolean hasOverrides = override != null; + if (hasOverrides) { + knownKeys++; + override = processUnknownValue(override, arguments); + } + + // 获取merges + Object merge = input.get(MERGES); + boolean hasMerges = merge != null; + if (hasMerges) { + knownKeys++; + merge = processUnknownValue(merge, arguments); + } + + // 有其他意外参数 + if (input.size() > knownKeys) { + Map merges = new LinkedHashMap<>(); + // 会不会有一种可能,有笨比用户把模板和普通配置混合在了一起?再次遍历input后处理。 + for (Map.Entry inputEntry : input.entrySet()) { + ArgumentString inputKey = inputEntry.getKey(); + if (NON_TEMPLATE_ARGUMENTS.contains(inputKey)) continue; + Object key = inputKey.get(parentArguments); + if (key != null) { + merges.put(key.toString(), processUnknownValue(inputEntry.getValue(), arguments)); + } + } + if (hasMerges && merge instanceof Map rawMerges) { + Map mergeMap = (Map) rawMerges; + for (Map.Entry inputEntry : mergeMap.entrySet()) { + ArgumentString inputKey = inputEntry.getKey(); + Object key = inputKey.get(parentArguments); + if (key != null) { + merges.put(key.toString(), processUnknownValue(inputEntry.getValue(), arguments)); + } + } + } + return new TemplateProcessingResult( + templateList, + override, + merges, + arguments + ); + } else { + return new TemplateProcessingResult( + templateList, + override, + merge, + arguments + ); } - // 返回处理结果 - return new TemplateProcessingResult( - templateList, - overrides, - arguments - ); } // 合并参数 - private Map mergeArguments(@NotNull Map rawChildArguments, + @SuppressWarnings("unchecked") + private Map mergeArguments(@NotNull Map childArguments, @NotNull Map parentArguments) { - Map result = new HashMap<>(parentArguments); - // 我们遍历一下当前节点下的所有参数,这些参数可能含有内嵌参数。所以需要对参数map先处理一次后再合并 - // arguments: - // argument_1: "{parent_argument}" - for (Map.Entry argumentEntry : rawChildArguments.entrySet()) { - // 获取最终的string形式参数 - String placeholder = LEFT_BRACKET + argumentEntry.getKey() + RIGHT_BRACKET; + Map result = new LinkedHashMap<>(parentArguments); + for (Map.Entry argumentEntry : childArguments.entrySet()) { + Object placeholderObj = argumentEntry.getKey().get(result); + if (placeholderObj == null) continue; + String placeholder = placeholderObj.toString(); // 父亲参数最大 if (result.containsKey(placeholder)) continue; - Object rawArgument = argumentEntry.getValue(); - if (rawArgument instanceof Map mapArgument) { - // 此参数是一个map,那么对map应用模板,然后再根据map是否含有type等参数,判别其是否为带名特殊参数 - Map nestedResult = new LinkedHashMap<>(); - processMap(MiscUtils.castToMap(mapArgument, false), parentArguments, (obj) -> { - // 如果有人往arguments下塞了一个模板,则模板类型应为map - if (obj instanceof Map mapResult) { - nestedResult.putAll(MiscUtils.castToMap(mapResult, false)); - } else { - throw new IllegalArgumentException("Invalid template used. Input: " + GsonHelper.get().toJson(mapArgument) + ". Template: " + GsonHelper.get().toJson(obj)); - } - }); - result.put(placeholder, TemplateArguments.fromMap(nestedResult)); - } else if (rawArgument instanceof List listArgument) { - // 此参数是一个list,那么只需要应用模板即可 - List nestedResult = new ArrayList<>(); - for (Object item : listArgument) { - processUnknownTypeMember(item, parentArguments, nestedResult::add); - } - result.put(placeholder, new ListTemplateArgument(nestedResult)); - } else if (rawArgument == null) { - // 使用 null 覆写其父参数内容 - result.put(placeholder, NullTemplateArgument.INSTANCE); - } else if (rawArgument instanceof Number number) { - result.put(placeholder, new ObjectTemplateArgument(number)); - } else { - // 将参数字符串化后,应用参数再放入 - Object applied = applyArgument(rawArgument.toString(), parentArguments); - result.put(placeholder, new ObjectTemplateArgument(applied)); + Object processedPlaceholderValue = processUnknownValue(argumentEntry.getValue(), result); + switch (processedPlaceholderValue) { + case Map map -> result.put(placeholder, TemplateArguments.fromMap(MiscUtils.castToMap(map, false))); + case List listArgument -> result.put(placeholder, new ListTemplateArgument((List) listArgument)); + case null -> result.put(placeholder, NullTemplateArgument.INSTANCE); + default -> result.put(placeholder, new ObjectTemplateArgument(processedPlaceholderValue)); } } return result; } - // 将某个输入变成最终的结果,可以是string->string,也可以是string->map/list - private Object applyArgument(String input, Map arguments) { - StringBuilder result = new StringBuilder(); - Matcher matcher = ARGUMENT_PATTERN.matcher(input); - boolean first = true; - while (matcher.find()) { - String placeholder = matcher.group(); - Supplier replacer = arguments.get(placeholder); - if (replacer == null) { - matcher.appendReplacement(result, placeholder); - continue; - } - if (first) { - first = false; - if (input.length() == placeholder.length()) { - return replacer.get(); - } else { - matcher.appendReplacement(result, replacer.get().toString()); - } - } else { - matcher.appendReplacement(result, replacer.get().toString()); - } - } - matcher.appendTail(result); - return result.toString(); - } - private record TemplateProcessingResult( List templates, - Map overrides, + Object overrides, + Object merges, Map arguments ) {} } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java index 83e0853a5..910678475 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractCommonContext.java @@ -33,7 +33,7 @@ public abstract class AbstractCommonContext implements Context { public TagResolver[] tagResolvers() { if (this.tagResolvers == null) { this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new I18NTag(this), new NamedArgumentTag(this), - new PlaceholderTag(null), new ExpressionTag(this), new GlobalVariableTag(this)}; + new PlaceholderTag(this), new ExpressionTag(this), new GlobalVariableTag(this)}; } return this.tagResolvers; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java index e71cf975b..72667d538 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/PlayerOptionalContext.java @@ -57,7 +57,7 @@ public class PlayerOptionalContext extends AbstractChainParameterContext impleme @NotNull public TagResolver[] tagResolvers() { if (this.tagResolvers == null) { - this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new PlaceholderTag(this.player), new I18NTag(this), + this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, new PlaceholderTag(this), new I18NTag(this), new NamedArgumentTag(this), new ExpressionTag(this), new GlobalVariableTag(this)}; } return this.tagResolvers; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java index cc4f2d761..affc6cd72 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/ViewerContext.java @@ -53,19 +53,15 @@ public class ViewerContext implements RelationalContext { @Override public TagResolver[] tagResolvers() { if (this.tagResolvers == null) { - Player optionalOwner = null; - if (this.owner instanceof PlayerOptionalContext context) { - optionalOwner = context.player(); - } - if (optionalOwner != null && this.viewer.player != null) { - this.tagResolvers = new TagResolver[]{new RelationalPlaceholderTag(optionalOwner, this.viewer.player), + if (this.owner instanceof PlayerOptionalContext context && context.player != null && this.viewer.player != null) { + this.tagResolvers = new TagResolver[]{new RelationalPlaceholderTag(context.player, this.viewer.player, this), ShiftTag.INSTANCE, ImageTag.INSTANCE, - new PlaceholderTag(optionalOwner), new ViewerPlaceholderTag(this.viewer.player()), + new PlaceholderTag(this.owner), new ViewerPlaceholderTag(this.viewer), new NamedArgumentTag(this.owner), new ViewerNamedArgumentTag(this.viewer), new I18NTag(this), new ExpressionTag(this), new GlobalVariableTag(this)}; } else { this.tagResolvers = new TagResolver[]{ShiftTag.INSTANCE, ImageTag.INSTANCE, - new PlaceholderTag(optionalOwner), new ViewerPlaceholderTag(this.viewer.player()), + new PlaceholderTag(this.owner), new ViewerPlaceholderTag(this.viewer), new NamedArgumentTag(this.owner), new ViewerNamedArgumentTag(this.viewer), new I18NTag(this), new ExpressionTag(this), new GlobalVariableTag(this)}; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslator.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslator.java index de6febf2f..decab7f42 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslator.java @@ -21,9 +21,5 @@ public interface MiniMessageTranslator extends Translator, Examinable { return renderer().render(component, locale); } - @NotNull Iterable sources(); - - boolean addSource(final @NotNull Translator source); - - boolean removeSource(final @NotNull Translator source); + boolean setSource(final @NotNull Translator source); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslatorImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslatorImpl.java index d096d47ca..8bbfe0ecc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslatorImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MiniMessageTranslatorImpl.java @@ -11,17 +11,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.text.MessageFormat; -import java.util.Collections; import java.util.Locale; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; public class MiniMessageTranslatorImpl implements MiniMessageTranslator { private static final Key NAME = Key.key(net.momirealms.craftengine.core.util.Key.DEFAULT_NAMESPACE, "main"); static final MiniMessageTranslatorImpl INSTANCE = new MiniMessageTranslatorImpl(); - final TranslatableComponentRenderer renderer = TranslatableComponentRenderer.usingTranslationSource(this); - private final Set sources = Collections.newSetFromMap(new ConcurrentHashMap<>()); + protected final TranslatableComponentRenderer renderer = TranslatableComponentRenderer.usingTranslationSource(this); + private Translator source; @Override public @NotNull Key name() { @@ -30,7 +27,7 @@ public class MiniMessageTranslatorImpl implements MiniMessageTranslator { @Override public @NotNull TriState hasAnyTranslations() { - if (!this.sources.isEmpty()) { + if (this.source != null) { return TriState.TRUE; } return TriState.FALSE; @@ -44,33 +41,20 @@ public class MiniMessageTranslatorImpl implements MiniMessageTranslator { @Override public @Nullable Component translate(@NotNull TranslatableComponent component, @NotNull Locale locale) { - for (final Translator source : this.sources) { - final Component translation = source.translate(component, locale); - if (translation != null) { - return translation; - } + if (this.source != null) { + return this.source.translate(component, locale); } return null; } @Override - public @NotNull Iterable sources() { - return Collections.unmodifiableSet(this.sources); - } - - @Override - public boolean addSource(final @NotNull Translator source) { - if (source == this) throw new IllegalArgumentException("MiniMessageTranslationSource"); - return this.sources.add(source); - } - - @Override - public boolean removeSource(final @NotNull Translator source) { - return this.sources.remove(source); + public boolean setSource(@NotNull Translator source) { + this.source = source; + return true; } @Override public @NotNull Stream examinableProperties() { - return Stream.of(ExaminableProperty.of("sources", this.sources)); + return Stream.of(ExaminableProperty.of("source", this.source)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index d73c40551..6a494b950 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -9,26 +9,28 @@ import net.momirealms.craftengine.core.plugin.Plugin; import net.momirealms.craftengine.core.plugin.PluginProperties; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; +import net.momirealms.craftengine.core.plugin.config.TranslationConfigConstructor; import net.momirealms.craftengine.core.plugin.text.minimessage.IndexedArgumentTag; import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.Pair; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.representer.Representer; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; -import java.util.stream.Stream; public class TranslationManagerImpl implements TranslationManager { private static final Locale DEFAULT_LOCALE = Locale.ENGLISH; @@ -38,13 +40,14 @@ public class TranslationManagerImpl implements TranslationManager { private final Path translationsDirectory; private final String langVersion; private final String[] supportedLanguages; - private final Map translationFallback = new LinkedHashMap<>(); + private final Map translationFallback = new LinkedHashMap<>(); private Locale forcedLocale = null; private Locale selectedLocale = DEFAULT_LOCALE; private MiniMessageTranslationRegistry registry; private final Map clientLangData = new HashMap<>(); private final LangParser langParser; private final I18NParser i18nParser; + private Map cachedTranslations = Map.of(); public TranslationManagerImpl(Plugin plugin) { instance = this; @@ -54,7 +57,7 @@ public class TranslationManagerImpl implements TranslationManager { this.supportedLanguages = PluginProperties.getValue("supported-languages").split(","); this.langParser = new LangParser(); this.i18nParser = new I18NParser(); - Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); + Yaml yaml = new Yaml(new TranslationConfigConstructor(new LoaderOptions())); try (InputStream is = plugin.resourceStream("translations/en.yml")) { this.translationFallback.putAll(yaml.load(is)); } catch (IOException e) { @@ -81,12 +84,7 @@ public class TranslationManagerImpl implements TranslationManager { public void reload() { // clear old data this.clientLangData.clear(); - - // remove any previous registry - if (this.registry != null) { - MiniMessageTranslator.translator().removeSource(this.registry); - this.installed.clear(); - } + this.installed.clear(); // save resources for (String lang : this.supportedLanguages) { @@ -95,8 +93,10 @@ public class TranslationManagerImpl implements TranslationManager { this.registry = MiniMessageTranslationRegistry.create(Key.key(net.momirealms.craftengine.core.util.Key.DEFAULT_NAMESPACE, "main"), AdventureHelper.miniMessage()); this.registry.defaultLocale(DEFAULT_LOCALE); - this.loadFromFileSystem(this.translationsDirectory, false); - MiniMessageTranslator.translator().addSource(this.registry); + + this.loadFromFileSystem(this.translationsDirectory); + this.loadFromCache(); + MiniMessageTranslator.translator().setSource(this.registry); this.setSelectedLocale(); } @@ -138,89 +138,65 @@ public class TranslationManagerImpl implements TranslationManager { return MiniMessageTranslator.render(component, locale); } - public void loadFromFileSystem(Path directory, boolean suppressDuplicatesError) { - List translationFiles; - try (Stream stream = Files.list(directory)) { - translationFiles = stream.filter(TranslationManagerImpl::isTranslationFile).collect(Collectors.toList()); - } catch (IOException e) { - translationFiles = Collections.emptyList(); - } - - if (translationFiles.isEmpty()) { - return; - } - - Map> loaded = new HashMap<>(); - for (Path translationFile : translationFiles) { - try { - Pair> result = loadTranslationFile(translationFile); - loaded.put(result.left(), result.right()); - } catch (Exception e) { - if (!suppressDuplicatesError || !isAdventureDuplicatesException(e)) { - this.plugin.logger().warn("Error loading locale file: " + translationFile.getFileName(), e); - } + private void loadFromCache() { + for (Map.Entry entry : this.cachedTranslations.entrySet()) { + Locale locale = TranslationManager.parseLocale(entry.getKey()); + if (locale == null) { + this.plugin.logger().warn("Unknown locale '" + entry.getKey() + "' - unable to register."); + continue; } - } - - // try registering the locale without a country code - if we don't already have a registration for that - loaded.forEach((locale, bundle) -> { + Map translations = entry.getValue().translations(); + this.registry.registerAll(locale, translations); + this.installed.add(locale); Locale localeWithoutCountry = Locale.of(locale.getLanguage()); if (!locale.equals(localeWithoutCountry) && !localeWithoutCountry.equals(DEFAULT_LOCALE) && this.installed.add(localeWithoutCountry)) { try { - this.registry.registerAll(localeWithoutCountry, bundle); + this.registry.registerAll(localeWithoutCountry, translations); } catch (IllegalArgumentException e) { // ignore } } - }); - } - - public static boolean isTranslationFile(Path path) { - return path.getFileName().toString().endsWith(".yml"); - } - - private static boolean isAdventureDuplicatesException(Exception e) { - return e instanceof IllegalArgumentException && (e.getMessage().startsWith("Invalid key") || e.getMessage().startsWith("Translation already exists")); - } - - @SuppressWarnings("unchecked") - private Pair> loadTranslationFile(Path translationFile) { - String fileName = translationFile.getFileName().toString(); - String localeString = fileName.substring(0, fileName.length() - ".yml".length()); - Locale locale = TranslationManager.parseLocale(localeString); - if (locale == null) { - throw new IllegalStateException("Unknown locale '" + localeString + "' - unable to register."); } + } - Map bundle = new HashMap<>(); - Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); - try (InputStreamReader inputStream = new InputStreamReader(new FileInputStream(translationFile.toFile()), StandardCharsets.UTF_8)) { - Map map = yaml.load(inputStream); - String langVersion = map.getOrDefault("lang-version", "").toString(); - if (!langVersion.equals(this.langVersion)) { - map = updateLangFile(map, translationFile); - } - - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() instanceof String str) { - bundle.put(entry.getKey(), str); - } else if (entry.getValue() instanceof List list) { - List strList = (List) list; - StringJoiner stringJoiner = new StringJoiner(""); - for (String str : strList) { - stringJoiner.add(str); + public void loadFromFileSystem(Path directory) { + Map previousTranslations = this.cachedTranslations; + this.cachedTranslations = new HashMap<>(); + try { + Files.walkFileTree(directory, new SimpleFileVisitor<>() { + @Override + public @NotNull FileVisitResult visitFile(@NotNull Path path, @NotNull BasicFileAttributes attrs) { + String fileName = path.getFileName().toString(); + if (Files.isRegularFile(path) && fileName.endsWith(".yml")) { + String localeName = fileName.substring(0, fileName.length() - ".yml".length()); + CachedTranslation cachedFile = previousTranslations.get(localeName); + long lastModifiedTime = attrs.lastModifiedTime().toMillis(); + long size = attrs.size(); + if (cachedFile != null && cachedFile.lastModified() == lastModifiedTime && cachedFile.size() == size) { + TranslationManagerImpl.this.cachedTranslations.put(localeName, cachedFile); + } else { + try (InputStreamReader inputStream = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { + Yaml yaml = new Yaml(new TranslationConfigConstructor(new LoaderOptions())); + Map data = yaml.load(inputStream); + if (data == null) return FileVisitResult.CONTINUE; + String langVersion = data.getOrDefault("lang-version", ""); + if (!langVersion.equals(TranslationManagerImpl.this.langVersion)) { + data = updateLangFile(data, path); + } + cachedFile = new CachedTranslation(data, lastModifiedTime, size); + TranslationManagerImpl.this.cachedTranslations.put(localeName, cachedFile); + } catch (IOException e) { + TranslationManagerImpl.this.plugin.logger().severe("Error while reading translation file: " + path, e); + return FileVisitResult.CONTINUE; + } + } } - bundle.put(entry.getKey(), stringJoiner.toString()); + return FileVisitResult.CONTINUE; } - } - - this.registry.registerAll(locale, bundle); - this.installed.add(locale); + }); } catch (IOException e) { - this.plugin.logger().warn(translationFile, "Error loading translation file", e); + this.plugin.logger().warn("Failed to load translation file from folder", e); } - - return Pair.of(locale, bundle); } @Override @@ -230,19 +206,20 @@ public class TranslationManagerImpl implements TranslationManager { this.plugin.senderFactory().console().sendMessage(AdventureHelper.miniMessage().deserialize(translation, new IndexedArgumentTag(Arrays.stream(args).map(Component::text).toList()))); } - private Map updateLangFile(Map previous, Path translationFile) throws IOException { + private Map updateLangFile(Map previous, Path translationFile) throws IOException { DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); options.setPrettyFlow(true); options.setIndent(2); options.setSplitLines(false); options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED); - Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions()), new Representer(options), options); - LinkedHashMap newFileContents = new LinkedHashMap<>(); - try (InputStream is = plugin.resourceStream("translations/" + translationFile.getFileName())) { - Map newMap = yaml.load(is); + Yaml yaml = new Yaml(new StringKeyConstructor(translationFile, new LoaderOptions()), new Representer(options), options); + LinkedHashMap newFileContents = new LinkedHashMap<>(); + try (InputStream is = this.plugin.resourceStream("translations/" + translationFile.getFileName())) { + Map newMap = yaml.load(is); newFileContents.putAll(this.translationFallback); newFileContents.putAll(newMap); + // 思考是否值得特殊处理list类型的dump?似乎并没有这个必要。用户很少会使用list类型,且dump后只改变YAML结构而不影响游戏内效果。 newFileContents.putAll(previous); newFileContents.put("lang-version", this.langVersion); String yamlString = yaml.dump(newFileContents); @@ -332,4 +309,7 @@ public class TranslationManagerImpl implements TranslationManager { TranslationManagerImpl.this.addClientTranslation(langId, sectionData); } } + + private record CachedTranslation(Map translations, long lastModified, long size) { + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java index 224a27f81..15e0aa919 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/EntityPacketHandler.java @@ -16,4 +16,7 @@ public interface EntityPacketHandler { default void handleMoveAndRotate(NetWorkUser user, NMSPacketEvent event, Object packet) { } + + default void handleMove(NetWorkUser user, NMSPacketEvent event, Object packet) { + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java index c326b284b..019d915e6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/PlaceholderTag.java @@ -5,17 +5,17 @@ import net.kyori.adventure.text.minimessage.ParsingException; import net.kyori.adventure.text.minimessage.tag.Tag; import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; -import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.util.AdventureHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class PlaceholderTag implements TagResolver { - private final Player player; + private final net.momirealms.craftengine.core.plugin.context.Context context; - public PlaceholderTag(@Nullable Player player) { - this.player = player; + public PlaceholderTag(@NotNull net.momirealms.craftengine.core.plugin.context.Context context) { + this.context = context; } @Override @@ -23,8 +23,10 @@ public class PlaceholderTag implements TagResolver { if (!this.has(name) || !CraftEngine.instance().compatibilityManager().hasPlaceholderAPI()) { return null; } - String placeholder = "%" + arguments.popOr("No argument placeholder provided") + "%"; - String parsed = CraftEngine.instance().compatibilityManager().parse(player, placeholder); + String rawArgument = arguments.popOr("No argument relational placeholder provided").toString(); + if (rawArgument.contains("<")) rawArgument = AdventureHelper.resolvePlainStringTags(rawArgument, this.context.tagResolvers()); + String placeholder = "%" + rawArgument + "%"; + String parsed = this.context instanceof PlayerOptionalContext playerOptionalContext ? CraftEngine.instance().compatibilityManager().parse(playerOptionalContext.player(), placeholder) : CraftEngine.instance().compatibilityManager().parse(null, placeholder); if (parsed.equals(placeholder)) { parsed = arguments.popOr("No default papi value provided").toString(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/RelationalPlaceholderTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/RelationalPlaceholderTag.java index 07f175b6d..4815ec310 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/RelationalPlaceholderTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/RelationalPlaceholderTag.java @@ -7,6 +7,8 @@ import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.RelationalContext; import net.momirealms.craftengine.core.util.AdventureHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,10 +16,12 @@ import org.jetbrains.annotations.Nullable; public class RelationalPlaceholderTag implements TagResolver { private final Player player1; private final Player player2; + private final RelationalContext context; - public RelationalPlaceholderTag(@NotNull Player player1, @NotNull Player player2) { + public RelationalPlaceholderTag(@NotNull Player player1, @NotNull Player player2, RelationalContext context) { this.player1 = player1; this.player2 = player2; + this.context = context; } @Override @@ -25,8 +29,10 @@ public class RelationalPlaceholderTag implements TagResolver { if (!this.has(name) || !CraftEngine.instance().compatibilityManager().hasPlaceholderAPI()) { return null; } - String placeholder = "%" + arguments.popOr("No argument placeholder provided") + "%"; - String parsed = CraftEngine.instance().compatibilityManager().parse(player1, player2, placeholder); + String rawArgument = arguments.popOr("No argument placeholder provided").toString(); + if (rawArgument.contains("<")) rawArgument = AdventureHelper.resolvePlainStringTags(rawArgument, this.context.tagResolvers()); + String placeholder = "%" + rawArgument + "%"; + String parsed = CraftEngine.instance().compatibilityManager().parse(this.player1, this.player2, placeholder); if (parsed.equals(placeholder)) { parsed = arguments.popOr("No default papi value provided").toString(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java index 397a891ff..383c4ec12 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/text/minimessage/ViewerPlaceholderTag.java @@ -1,12 +1,11 @@ package net.momirealms.craftengine.core.plugin.text.minimessage; -import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Context; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class ViewerPlaceholderTag extends PlaceholderTag { - public ViewerPlaceholderTag(@Nullable Player player) { + public ViewerPlaceholderTag(@NotNull Context player) { super(player); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index c404f15a8..3ed1f6048 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -316,6 +316,11 @@ public class AdventureHelper { return true; } + public static String resolvePlainStringTags(String raw, TagResolver... resolvers) { + Component resultComponent = AdventureHelper.customMiniMessage().deserialize(raw, resolvers); + return AdventureHelper.plainTextContent(resultComponent); + } + public static Component replaceText(Component text, Map replacements) { String patternString = replacements.keySet().stream() .map(Pattern::quote) diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java index 208625927..90abef1e1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java @@ -11,19 +11,16 @@ public class CharacterUtils { private CharacterUtils() {} public static char[] decodeUnicodeToChars(String unicodeString) { - String processedString = unicodeString.replace("\\u", ""); - int length = processedString.length() / 4; - char[] chars = new char[length]; - for (int i = 0; i < length; i++) { - String hex = processedString.substring(i * 4, i * 4 + 4); + int count = unicodeString.length() / 6; + if (unicodeString.length() % 6 != 0) { + throw new LocalizedResourceConfigException("warning.config.image.invalid_unicode_string_length"); + } + char[] chars = new char[count]; + for (int i = 0, j = 0; j < count; i += 6, j++) { + String hex = unicodeString.substring(i + 2, i + 6); try { int codePoint = Integer.parseInt(hex, 16); - if (Character.isSupplementaryCodePoint(codePoint)) { - chars[i] = Character.highSurrogate(codePoint); - chars[++i] = Character.lowSurrogate(codePoint); - } else { - chars[i] = (char) codePoint; - } + chars[j] = (char) codePoint; } catch (NumberFormatException e) { throw new LocalizedResourceConfigException("warning.config.image.invalid_hex_value", e, hex); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/DamageSource.java b/core/src/main/java/net/momirealms/craftengine/core/util/DamageSource.java new file mode 100644 index 000000000..738295b77 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/DamageSource.java @@ -0,0 +1,57 @@ +package net.momirealms.craftengine.core.util; + +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +public enum DamageSource { + BLOCK_EXPLOSION, + CAMPFIRE, + CONTACT, + CRAMMING, + CUSTOM, + DROWNING, + DRYOUT, + ENTITY_ATTACK, + ENTITY_EXPLOSION, + ENTITY_SWEEP_ATTACK, + FALL, + FALLING_BLOCK, + FIRE, + FIRE_TICK, + FLY_INTO_WALL, + FREEZE, + HOT_FLOOR, + KILL, + LAVA, + LIGHTNING, + MAGIC, + MELTING, + POISON, + PROJECTILE, + SONIC_BOOM, + STARVATION, + SUFFOCATION, + SUICIDE, + THORNS, + VOID, + WITHER, + WORLD_BORDER; + + public static final Map BY_NAME = new HashMap<>(); + + static { + for (DamageSource cause : values()) { + BY_NAME.put(cause.name().toLowerCase(Locale.ENGLISH), cause); + BY_NAME.put(cause.name(), cause); + } + } + + @Nullable + public static DamageSource byName(String name) { + return BY_NAME.get(name); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java index 1d2a9a5b6..f82b81e7f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java @@ -1,5 +1,8 @@ package net.momirealms.craftengine.core.util; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.momirealms.craftengine.core.pack.ResourceLocation; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -57,4 +60,28 @@ public class FileUtils { throw new RuntimeException("Failed to traverse directory: " + configFolder, e); } } + + public static List collectOverlays(Path resourcePackFolder) throws IOException { + List folders = new ObjectArrayList<>(); + folders.add(resourcePackFolder); + try (Stream paths = Files.list(resourcePackFolder)) { + folders.addAll(paths + .filter(Files::isDirectory) + .filter(path -> !path.getFileName().toString().equals("assets")) + .filter(path -> Files.exists(path.resolve("assets"))) + .toList()); + } + return folders; + } + + public static List collectNamespaces(Path assetsFolder) throws IOException { + List folders; + try (Stream paths = Files.list(assetsFolder)) { + folders = new ObjectArrayList<>(paths + .filter(Files::isDirectory) + .filter(path -> ResourceLocation.isValidNamespace(path.getFileName().toString())) + .toList()); + } + return folders; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java index d3c9b178b..572c8b5ee 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java @@ -50,6 +50,22 @@ public class MiscUtils { return list; } + @SuppressWarnings("unchecked") + public static List getAsList(Object o, Class clazz) { + if (o instanceof List list) { + if (list.isEmpty()) { + return List.of(); + } + if (clazz.isInstance(list.getFirst())) { + return (List) list; + } + } + if (clazz.isInstance(o)) { + return List.of((T) o); + } + return List.of(); + } + public static Vector3f getAsVector3f(Object o, String option) { if (o == null) return new Vector3f(); if (o instanceof List list && list.size() == 3) { @@ -83,4 +99,33 @@ public class MiscUtils { } } } + + @SuppressWarnings("unchecked") + public static void deepMergeMaps(Map baseMap, Map mapToMerge) { + for (Map.Entry entry : mapToMerge.entrySet()) { + String key = entry.getKey(); + if (key.length() > 2 && key.charAt(0) == '$' && key.charAt(1) == '$') { + Object value = entry.getValue(); + baseMap.put(key.substring(1), value); + } else { + Object value = entry.getValue(); + if (baseMap.containsKey(key)) { + Object existingValue = baseMap.get(key); + if (existingValue instanceof Map && value instanceof Map) { + Map existingMap = (Map) existingValue; + Map newMap = (Map) value; + deepMergeMaps(existingMap, newMap); + } else if (existingValue instanceof List && value instanceof List) { + List existingList = (List) existingValue; + List newList = (List) value; + existingList.addAll(newList); + } else { + baseMap.put(key, value); + } + } else { + baseMap.put(key, value); + } + } + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java index 12a92f3f0..ea6759cfb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ReflectionUtils.java @@ -494,6 +494,15 @@ public class ReflectionUtils { } } + public static MethodHandle unreflectSetter(Field field) throws IllegalAccessException { + try { + return LOOKUP.unreflectSetter(field); + } catch (IllegalAccessException e) { + field.setAccessible(true); + return LOOKUP.unreflectSetter(field); + } + } + public static MethodHandle unreflectMethod(Method method) throws IllegalAccessException { try { return LOOKUP.unreflect(method); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index f49424a47..1a20bf82d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -47,6 +47,8 @@ public interface World { playBlockSound(location, data.id(), data.volume(), data.pitch()); } + void levelEvent(int id, BlockPos pos, int data); + void spawnParticle(Position location, Key particle, int count, double xOffset, double yOffset, double zOffset, double speed, @Nullable ParticleData extraData, @NotNull Context context); long time(); diff --git a/gradle.properties b/gradle.properties index 5b9bbed93..7be6991a5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.56 -config_version=34 -lang_version=14 +project_version=0.0.57 +config_version=37 +lang_version=16 project_group=net.momirealms latest_supported_version=1.21.5 @@ -40,8 +40,8 @@ zstd_version=1.5.7-2 commons_io_version=2.18.0 commons_imaging_version=1.0.0-alpha6 commons_lang3_version=3.17.0 -sparrow_nbt_version=0.9.0 -sparrow_util_version=0.47 +sparrow_nbt_version=0.9.1 +sparrow_util_version=0.49.1 fastutil_version=8.5.15 netty_version=4.1.121.Final joml_version=1.10.8 @@ -51,7 +51,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 anti_grief_version=0.17 -nms_helper_version=0.66.12 +nms_helper_version=0.67.11 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23