diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 7426c520a..78efcd56d 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -58,6 +58,8 @@ dependencies { compileOnly("org.bstats:bstats-bukkit:${rootProject.properties["bstats_version"]}") // Aho-Corasick java implementation compileOnly("org.ahocorasick:ahocorasick:${rootProject.properties["ahocorasick_version"]}") + // authlib + compileOnly("com.mojang:authlib:${rootProject.properties["authlib_version"]}") } java { @@ -96,6 +98,7 @@ tasks { relocate("com.ezylang.evalex", "net.momirealms.craftengine.libraries.evalex") relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs") relocate("org.apache.commons", "net.momirealms.craftengine.libraries.commons") + relocate("io.leangen.geantyref", "net.momirealms.craftengine.libraries.geantyref") } } diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts index 957f7f6b1..110a0b229 100644 --- a/bukkit/compatibility/build.gradle.kts +++ b/bukkit/compatibility/build.gradle.kts @@ -34,7 +34,7 @@ dependencies { // ModelEngine compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.8") // BetterModels - compileOnly("io.github.toxicity188:BetterModel:1.4.2") + compileOnly("io.github.toxicity188:BetterModel:1.7.0") // MMOItems compileOnly("net.Indyuce:MMOItems-API:6.10-SNAPSHOT") compileOnly("io.lumine:MythicLib-dist:1.6.2-SNAPSHOT") 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 0d6f63e8e..a3c2eb4dd 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 @@ -210,7 +210,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager { Plugin fastAsyncWorldEdit = Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit"); String version = VersionHelper.isPaper() ? fastAsyncWorldEdit.getPluginMeta().getVersion() : fastAsyncWorldEdit.getDescription().getVersion(); if (!this.fastAsyncWorldEditVersionCheck(version)) { - if (VersionHelper.isOrAbove1_20_3()) { this.plugin.logger().severe(""); if (Locale.getDefault() == Locale.SIMPLIFIED_CHINESE) { diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/CustomFishingProvider.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/CustomFishingProvider.java index e32e03631..6d1300ded 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/CustomFishingProvider.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/CustomFishingProvider.java @@ -4,20 +4,33 @@ import net.momirealms.craftengine.core.item.ExternalItemProvider; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.customfishing.api.BukkitCustomFishingPlugin; import net.momirealms.customfishing.api.mechanic.context.Context; +import net.momirealms.customfishing.api.mechanic.context.ContextKeys; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; +import java.util.Optional; + public class CustomFishingProvider implements ExternalItemProvider { @Override public String plugin() { return "CustomFishing"; } + @SuppressWarnings("UnstableApiUsage") @Nullable @Override public ItemStack build(String id, ItemBuildContext context) { - return BukkitCustomFishingPlugin.getInstance().getItemManager() - .buildInternal(Context.player(((Player) context.player().platformPlayer())), id); + Context ctx = Context.player( + (Player) Optional.ofNullable(context.player()) + .map(net.momirealms.craftengine.core.entity.player.Player::platformPlayer) + .orElse(null) + ); + return BukkitCustomFishingPlugin.getInstance().getItemManager().buildInternal(ctx.arg(ContextKeys.ID, id), id); + } + + @Override + public String id(ItemStack item) { + return BukkitCustomFishingPlugin.getInstance().getItemManager().getCustomFishingItemID(item); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MMOItemsProvider.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MMOItemsProvider.java index c466f82ca..49d38b9f9 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MMOItemsProvider.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/MMOItemsProvider.java @@ -9,8 +9,6 @@ import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; -import java.util.Locale; - import static java.util.Objects.requireNonNull; public class MMOItemsProvider implements ExternalItemProvider { @@ -23,7 +21,12 @@ public class MMOItemsProvider implements ExternalItemProvider { @Override public @Nullable ItemStack build(String id, ItemBuildContext context) { String[] split = id.split(":", 2); - MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), split[1].toUpperCase(Locale.ENGLISH)); + MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), split[1].toUpperCase()); return mmoItem == null ? new ItemStack(Material.AIR) : requireNonNull(mmoItem.newBuilder().build()); } + + @Override + public String id(ItemStack item) { + return MMOItems.getType(item) + ":" + MMOItems.getID(item); + } } 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 index 8b01bc237..21df07ef8 100644 --- 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 @@ -22,4 +22,12 @@ public class MythicMobsProvider implements ExternalItemProvider { } return mythicBukkit.getItemManager().getItemStack(id); } + + @Override + public String id(ItemStack item) { + if (mythicBukkit == null || mythicBukkit.isClosed()) { + this.mythicBukkit = MythicBukkit.inst(); + } + return mythicBukkit.getItemManager().getMythicTypeFromItem(item); + } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/NeigeItemsProvider.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/NeigeItemsProvider.java index 9fe7d0f18..d4b79a345 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/NeigeItemsProvider.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/NeigeItemsProvider.java @@ -19,4 +19,9 @@ public class NeigeItemsProvider implements ExternalItemProvider { public ItemStack build(String id, ItemBuildContext context) { return ItemManager.INSTANCE.getItemStack(id, Optional.ofNullable(context.player()).map(it -> (Player) it.platformPlayer()).orElse(null)); } + + @Override + public String id(ItemStack item) { + return ItemManager.INSTANCE.getItemId(item); + } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelUtils.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelUtils.java index eb103dc80..73e568774 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelUtils.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelUtils.java @@ -1,13 +1,13 @@ package net.momirealms.craftengine.bukkit.compatibility.model.bettermodel; import kr.toxicity.model.api.BetterModel; -import kr.toxicity.model.api.data.renderer.BlueprintRenderer; +import kr.toxicity.model.api.data.renderer.ModelRenderer; import org.bukkit.entity.Entity; public class BetterModelUtils { public static void bindModel(Entity base, String id) { - BlueprintRenderer renderer = BetterModel.inst().modelManager().renderer(id); + ModelRenderer renderer = BetterModel.plugin().modelManager().renderer(id); if (renderer == null) { throw new NullPointerException("Could not find BetterModel blueprint " + 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 index 8c144b4c5..9c582cf1d 100644 --- 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 @@ -29,12 +29,10 @@ public class CraftEngineItemDrop extends ItemDrop implements IItemDrop { 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) { 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 index 9d59cab3a..22101993b 100644 --- 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 @@ -20,7 +20,6 @@ public class MythicMobsListener implements Listener { 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(); diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java index e08be5472..2263c7f25 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/FastAsyncWorldEditDelegate.java @@ -211,7 +211,6 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { int newStateId = ordinalToIbdID[newBlock.getOrdinal()]; int oldStateId = ordinalToIbdID[oldBlock.getOrdinal()]; this.brokenChunks.add(ChunkPos.of(chunkX, chunkZ)); - //CraftEngine.instance().debug(() -> "Processing block at " + blockX + ", " + blockY + ", " + blockZ + ": " + oldStateId + " -> " + newStateId); if (BlockStateUtils.isVanillaBlock(newStateId) && BlockStateUtils.isVanillaBlock(oldStateId)) return; try { CEChunk ceChunk = Optional.ofNullable(this.ceWorld.getChunkAtIfLoaded(chunkX, chunkZ)) @@ -231,7 +230,6 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent { private void saveAllChunks() { try { for (CEChunk ceChunk : this.chunksToSave) { - CraftEngine.instance().debug(() -> "Saving chunk " + ceChunk.chunkPos()); this.ceWorld.worldDataStorage().writeChunkAt(ceChunk.chunkPos(), ceChunk); } this.chunksToSave.clear(); diff --git a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java index f009e3583..9692a7953 100644 --- a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java +++ b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyInventoryUtils.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.util; import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryEvent; import org.bukkit.event.inventory.PrepareAnvilEvent; import org.bukkit.inventory.AnvilInventory; import org.bukkit.inventory.Inventory; @@ -65,4 +66,8 @@ public class LegacyInventoryUtils { public static void openWorkbench(Player player) { player.openWorkbench(null, true); } + + public static Player getPlayerFromInventoryEvent(InventoryEvent event) { + return (Player) event.getView().getPlayer(); + } } diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index cc6493188..9e4762b96 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -76,5 +76,6 @@ tasks { relocate("software.amazon.eventstream", "net.momirealms.craftengine.libraries.eventstream") relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs") relocate("org.apache.commons", "net.momirealms.craftengine.libraries.commons") + relocate("io.leangen.geantyref", "net.momirealms.craftengine.libraries.geantyref") } } diff --git a/bukkit/paper-loader/build.gradle.kts b/bukkit/paper-loader/build.gradle.kts index ab8645de3..ac2894f04 100644 --- a/bukkit/paper-loader/build.gradle.kts +++ b/bukkit/paper-loader/build.gradle.kts @@ -76,7 +76,6 @@ paper { // external models register("ModelEngine") { required = false } register("BetterModel") { required = false } - register("FreeMinecraftModels") { required = false } // external items register("NeigeItems") { required = false } @@ -149,5 +148,6 @@ tasks { relocate("software.amazon.eventstream", "net.momirealms.craftengine.libraries.eventstream") relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs") relocate("org.apache.commons", "net.momirealms.craftengine.libraries.commons") + relocate("io.leangen.geantyref", "net.momirealms.craftengine.libraries.geantyref") } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index bab5db3ec..f13128275 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -184,7 +184,7 @@ public final class CraftEngineBlocks { world.playBlockSound(position, state.settings().sounds().breakSound()); } if (sendParticles) { - FastNMS.INSTANCE.method$Level$levelEvent(world.serverWorld(), WorldEvents.BLOCK_BREAK_EFFECT, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), state.customBlockState().registryId()); + FastNMS.INSTANCE.method$LevelAccessor$levelEvent(world.serverWorld(), WorldEvents.BLOCK_BREAK_EFFECT, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), state.customBlockState().registryId()); } FastNMS.INSTANCE.method$Level$removeBlock(world.serverWorld(), LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), isMoving); return true; 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 c80db2fe4..113fc0d93 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 @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.CustomFurniture; import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.furniture.FurnitureExtraData; +import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.context.ContextHolder; @@ -276,7 +277,9 @@ public final class CraftEngineFurniture { .withParameter(DirectContextParameters.FURNITURE, furniture) .withOptionalParameter(DirectContextParameters.FURNITURE_ITEM, furniture.extraData().item().orElse(null)); if (player != null) { - builder.withParameter(DirectContextParameters.PLAYER, player); + Item itemInHand = player.getItemInHand(InteractionHand.MAIN_HAND); + builder.withParameter(DirectContextParameters.PLAYER, player) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand.isEmpty() ? null : itemInHand); } List> items = lootTable.getRandomItems(builder.build(), world, player); for (Item item : items) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineItems.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineItems.java index 2203f6e5b..64c628693 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineItems.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineItems.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.bukkit.api; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; -import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.util.Key; import org.bukkit.inventory.ItemStack; @@ -31,7 +31,7 @@ public final class CraftEngineItems { */ @Nullable public static CustomItem byItemStack(@NotNull ItemStack itemStack) { - if (ItemUtils.isEmpty(itemStack)) return null; + if (ItemStackUtils.isEmpty(itemStack)) return null; return BukkitItemManager.instance().wrap(itemStack).getCustomItem().orElse(null); } @@ -42,7 +42,7 @@ public final class CraftEngineItems { * @return true if it's a custom item */ public static boolean isCustomItem(@NotNull ItemStack itemStack) { - if (ItemUtils.isEmpty(itemStack)) return false; + if (ItemStackUtils.isEmpty(itemStack)) return false; return BukkitItemManager.instance().wrap(itemStack).isCustomItem(); } @@ -54,7 +54,7 @@ public final class CraftEngineItems { */ @Nullable public static Key getCustomItemId(@NotNull ItemStack itemStack) { - if (ItemUtils.isEmpty(itemStack)) return null; + if (ItemStackUtils.isEmpty(itemStack)) return null; return BukkitItemManager.instance().wrap(itemStack).customId().orElse(null); } } 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 70b587245..085c0059b 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 @@ -21,6 +21,7 @@ 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.ItemUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.WorldPosition; @@ -35,7 +36,6 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.world.GenericGameEvent; import org.bukkit.inventory.ItemStack; @@ -52,14 +52,6 @@ public final class BlockEventListener implements Listener { this.enableNoteBlockCheck = enableNoteBlockCheck; } - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - Object packet = this.manager.cachedUpdateTagsPacket; - if (packet != null) { - this.plugin.adapt(event.getPlayer()).sendPacket(packet, false); - } - } - @EventHandler(ignoreCancelled = true) public void onPlayerAttack(EntityDamageByEntityEvent event) { if (!VersionHelper.isOrAbove1_20_5()) { @@ -125,7 +117,7 @@ public final class BlockEventListener implements Listener { WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); - if (itemInHand != null) { + if (!ItemUtils.isEmpty(itemInHand)) { Optional> optionalCustomItem = itemInHand.getCustomItem(); if (optionalCustomItem.isPresent()) { Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); @@ -167,7 +159,7 @@ public final class BlockEventListener implements Listener { .withParameter(DirectContextParameters.CUSTOM_BLOCK_STATE, state) .withParameter(DirectContextParameters.EVENT, cancellable) .withParameter(DirectContextParameters.POSITION, position) - .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, ItemUtils.isEmpty(itemInHand) ? null : itemInHand) ); state.owner().value().execute(context, EventTrigger.BREAK); if (cancellable.isCancelled()) { @@ -189,7 +181,7 @@ public final class BlockEventListener implements Listener { .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withParameter(DirectContextParameters.POSITION, position) .withParameter(DirectContextParameters.PLAYER, serverPlayer) - .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand).build(); + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, ItemUtils.isEmpty(itemInHand) ? null : itemInHand).build(); for (LootTable lootTable : it.lootTables()) { for (Item item : lootTable.getRandomItems(lootContext, world, serverPlayer)) { world.dropItemNaturally(position, item); 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 5e5f77a9c..cab845559 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 @@ -94,7 +94,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { private BlockEventListener blockEventListener; private FallingBlockRemoveListener fallingBlockRemoveListener; // cached tag packet - Object cachedUpdateTagsPacket; + private Object cachedUpdateTagsPacket; private final List> blocksToDeceive = new ArrayList<>(); @@ -276,7 +276,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { } private void registerEmptyBlock() { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), Key.withDefaultNamespace("empty"))); + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), Key.withDefaultNamespace("empty"))); EmptyBlock emptyBlock = new EmptyBlock(Key.withDefaultNamespace("empty"), holder); holder.bindValue(emptyBlock); } @@ -397,6 +397,10 @@ public final class BukkitBlockManager extends AbstractBlockManager { } } + public Object cachedUpdateTagsPacket() { + return cachedUpdateTagsPacket; + } + public class BlockParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; @@ -500,13 +504,9 @@ public final class BukkitBlockManager extends AbstractBlockManager { Object clientBoundTags = settings.get("client-bound-tags"); if (clientBoundTags instanceof List list) { List clientSideTags = MiscUtils.getAsStringList(list).stream().filter(ResourceLocation::isValid).toList(); - try { - Object nmsBlock = CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(id)); - FastNMS.INSTANCE.method$IdMap$getId(MBuiltInRegistries.BLOCK, nmsBlock).ifPresent(i -> - BukkitBlockManager.this.clientBoundTags.put(i, clientSideTags)); - } catch (ReflectiveOperationException e) { - BukkitBlockManager.this.plugin.logger().warn("Unable to get block " + id, e); - } + Object nmsBlock = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(id)); + FastNMS.INSTANCE.method$IdMap$getId(MBuiltInRegistries.BLOCK, nmsBlock).ifPresent(i -> + BukkitBlockManager.this.clientBoundTags.put(i, clientSideTags)); } } } @@ -657,7 +657,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { private void recordVanillaNoteBlocks() { try { Object resourceLocation = KeyUtils.toResourceLocation(BlockKeys.NOTE_BLOCK); - Object block = CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, resourceLocation); + Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, resourceLocation); Object stateDefinition = CoreReflections.field$Block$StateDefinition.get(block); @SuppressWarnings("unchecked") ImmutableList states = (ImmutableList) CoreReflections.field$StateDefinition$states.get(stateDefinition); @@ -841,8 +841,8 @@ public final class BukkitBlockManager extends AbstractBlockManager { return FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath(key.namespace(), key.value()); } - private Object getBlockFromRegistry(Object resourceLocation) throws Exception { - return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, resourceLocation); + private Object getBlockFromRegistry(Object resourceLocation) { + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, resourceLocation); } private Key createRealBlockKey(Key replacedBlock, int index) { 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 df0f1a768..95a28e719 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 @@ -130,8 +130,8 @@ public final class BukkitCustomBlock extends AbstractCustomBlock { CoreReflections.field$BlockBehaviour$explosionResistance.set(nmsBlock, settings.resistance()); CoreReflections.field$BlockBehaviour$soundType.set(nmsBlock, SoundUtils.toSoundType(settings.sounds())); // 1.21.2以前要在init cache之前设定 isConditionallyFullOpaque + boolean isConditionallyFullOpaque = canOcclude & useShapeForLightOcclusion; if (!VersionHelper.isOrAbove1_21_2()) { - boolean isConditionallyFullOpaque = canOcclude & useShapeForLightOcclusion; CoreReflections.field$BlockStateBase$isConditionallyFullOpaque.set(nmsState, isConditionallyFullOpaque); } // init cache @@ -162,6 +162,9 @@ public final class BukkitCustomBlock extends AbstractCustomBlock { } else { CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(CoreReflections.field$BlockStateBase$cache.get(immutableBlockState.vanillaBlockState().handle()))); } + if (!isConditionallyFullOpaque) { + CoreReflections.field$BlockStateBase$opacityIfCached.set(nmsState, blockLight); + } } // set fluid later if (settings.fluidState()) { @@ -251,9 +254,8 @@ public final class BukkitCustomBlock extends AbstractCustomBlock { @Override public @NotNull CustomBlock build() { // create or get block holder - Holder.Reference holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() -> - ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id))); - return new BukkitCustomBlock(id, holder, properties, appearances, variantMapper, settings, events, behavior, lootTable); + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).getOrRegisterForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), this.id)); + return new BukkitCustomBlock(this.id, holder, this.properties, this.appearances, this.variantMapper, this.settings, this.events, this.behavior, this.lootTable); } } } 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 7e6bc299b..2ab895fe7 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 @@ -53,7 +53,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio public void onPlace(Object thisBlock, Object[] args, Callable superMethod) { Object world = args[1]; Object blockPos = args[2]; - FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 2); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(world, blockPos, thisBlock, 2); } @Override @@ -66,7 +66,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio return state; } if (this.delay != 0) { - FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(level, blockPos, thisBlock, this.delay); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, blockPos, thisBlock, this.delay); return state; } if (!canSurvive(thisBlock, new Object[] {state, level, blockPos}, () -> true)) { @@ -75,7 +75,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); world.playBlockSound(position, customState.settings().sounds().breakSound()); - FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId()); + FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId()); return MBlocks.AIR$defaultState; } return state; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java index a094bfd90..bd8b082c9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java @@ -7,6 +7,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MItems; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.MirrorUtils; import net.momirealms.craftengine.bukkit.util.RotationUtils; +import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; @@ -154,7 +155,7 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior { Object fluidType = FastNMS.INSTANCE.method$FluidState$getType(args[3]); if (!immutableBlockState.get(this.waterloggedProperty) && fluidType == MFluids.WATER) { FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], args[1], immutableBlockState.with(this.waterloggedProperty, true).customBlockState().handle(), 3); - FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(args[0], args[1], fluidType, 5); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[0], args[1], fluidType, 5); return true; } return false; @@ -172,4 +173,15 @@ public class BukkitBlockBehavior extends AbstractBlockBehavior { protected static final int updateShape$blockPos = VersionHelper.isOrAbove1_21_2() ? 3 : 4; protected static final int updateShape$neighborState = VersionHelper.isOrAbove1_21_2() ? 6 : 2; protected static final int updateShape$direction = VersionHelper.isOrAbove1_21_2() ? 4 : 1; + + protected static final int isPathFindable$type = VersionHelper.isOrAbove1_20_5() ? 1 : 3; + + @Override + public boolean isPathFindable(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(args[0]); + if (optionalCustomState.isEmpty()) return false; + BlockStateWrapper vanillaState = optionalCustomState.get().vanillaBlockState(); + if (vanillaState == null) return false; + return FastNMS.INSTANCE.method$BlockStateBase$isPathFindable(vanillaState.handle(), VersionHelper.isOrAbove1_20_5() ? null : args[1], VersionHelper.isOrAbove1_20_5() ? null : args[2], args[isPathFindable$type]); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index 30b980508..3f1d586b7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -26,6 +26,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key SLAB_BLOCK = Key.from("craftengine:slab_block"); public static final Key STAIRS_BLOCK = Key.from("craftengine:stairs_block"); public static final Key PRESSURE_PLATE_BLOCK = Key.from("craftengine:pressure_plate_block"); + public static final Key DOUBLE_BLOCK = Key.from("craftengine:double_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -50,5 +51,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(SLAB_BLOCK, SlabBlockBehavior.FACTORY); register(STAIRS_BLOCK, StairsBlockBehavior.FACTORY); register(PRESSURE_PLATE_BLOCK, PressurePlateBlockBehavior.FACTORY); + register(DOUBLE_BLOCK, DoubleBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index 29186f8b9..a2b0b3c0f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -22,6 +22,7 @@ import net.momirealms.craftengine.core.plugin.context.SimpleContext; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.ItemUtils; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.Vec3d; @@ -127,7 +128,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior { @Override public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { Item item = context.getItem(); - if (item == null || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) + if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) return InteractionResult.PASS; if (isMaxAge(state)) return InteractionResult.PASS; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java index 189bf0fca..768f01adf 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java @@ -1,8 +1,11 @@ package net.momirealms.craftengine.bukkit.block.behavior; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; @@ -15,8 +18,10 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.state.properties.DoorHinge; import net.momirealms.craftengine.core.block.state.properties.DoubleBlockHalf; +import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.sound.SoundData; @@ -32,6 +37,7 @@ import org.bukkit.block.data.Bisected; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Door; import org.bukkit.event.block.BlockRedstoneEvent; +import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; import javax.annotation.Nullable; @@ -111,13 +117,44 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior { net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); world.playBlockSound(position, customState.settings().sounds().breakSound()); - FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId()); + FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId()); return MBlocks.AIR$defaultState; } return blockState; } } + @Override + public Object playerWillDestroy(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object level = args[0]; + Object pos = args[1]; + Object state = args[2]; + Object player = args[3]; + ImmutableBlockState blockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); + if (blockState == null || blockState.isEmpty()) return superMethod.call(); + org.bukkit.entity.Player bukkitPlayer = FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player); + BukkitServerPlayer cePlayer = BukkitCraftEngine.instance().adapt(bukkitPlayer); + Item item = cePlayer.getItemInHand(InteractionHand.MAIN_HAND); + if (cePlayer.canInstabuild() || !BlockStateUtils.isCorrectTool(blockState, item)) { + preventDropFromBottomPart(level, pos, blockState, player); + } + return superMethod.call(); + } + + private void preventDropFromBottomPart(Object level, Object pos, ImmutableBlockState state, Object player) { + DoubleBlockHalf half = state.get(this.halfProperty); + if (half == DoubleBlockHalf.UPPER) { + Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$DOWN); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos); + ImmutableBlockState belowState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (belowState == null || belowState.isEmpty()) return; + Optional belowDoorBehavior = belowState.behavior().getAs(DoorBlockBehavior.class); + if (belowDoorBehavior.isEmpty() || belowState.get(this.halfProperty) != DoubleBlockHalf.LOWER) return; + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, MBlocks.AIR$defaultState, UpdateOption.builder().updateSuppressDrops().updateClients().updateNeighbors().build().flags()); + FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, player, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, belowState.customBlockState().registryId()); + } + } + @Override public void onExplosionHit(Object thisBlock, Object[] args, Callable superMethod) { if (this.canOpenByWindCharge && FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3])) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleBlockBehavior.java new file mode 100644 index 000000000..089510d9e --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleBlockBehavior.java @@ -0,0 +1,90 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.bukkit.world.BukkitWorld; +import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.block.state.properties.DoubleBlockHalf; +import net.momirealms.craftengine.core.item.context.BlockPlaceContext; +import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.*; + +import java.util.Map; +import java.util.concurrent.Callable; + + +public class DoubleBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final Property halfProperty; + + public DoubleBlockBehavior(CustomBlock customBlock, Property halfProperty) { + super(customBlock); + this.halfProperty = halfProperty; + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object level = args[updateShape$level]; + Object blockPos = args[updateShape$blockPos]; + Object blockState = args[0]; + + ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (customState == null || customState.isEmpty()) return blockState; + DoubleBlockHalf half = customState.get(this.halfProperty); + if (half == null) return blockState; + + // 获取另一半 + Object anotherHalfPos = FastNMS.INSTANCE.method$BlockPos$relative(blockPos, + half == DoubleBlockHalf.UPPER + ? CoreReflections.instance$Direction$DOWN + : CoreReflections.instance$Direction$UP + ); + Object anotherHalfState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, anotherHalfPos); + ImmutableBlockState anotherHalfCustomState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(anotherHalfState)); + if (anotherHalfCustomState != null && !anotherHalfCustomState.isEmpty()) return blockState; + + // 破坏 + BlockPos pos = LocationUtils.fromBlockPos(blockPos); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); + WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); + world.playBlockSound(position, customState.settings().sounds().breakSound()); + FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId()); + return MBlocks.AIR$defaultState; + } + + @Override + public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) { + World level = context.getLevel(); + BlockPos anotherHalfPos = context.getClickedPos().relative(Direction.UP); + BlockStateWrapper blockStateWrapper = state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState(); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level.serverWorld(), LocationUtils.toBlockPos(anotherHalfPos), blockStateWrapper.handle(), UpdateOption.Flags.UPDATE_CLIENTS); + } + + @Override + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { + World world = context.getLevel(); + BlockPos pos = context.getClickedPos(); + if (pos.y() < context.getLevel().worldHeight().getMaxBuildHeight() && world.getBlockAt(pos.above()).canBeReplaced(context)) { + return state.with(this.halfProperty, DoubleBlockHalf.LOWER); + } + return null; + } + + @SuppressWarnings("unchecked") + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Property half = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("half"), "warning.config.block.behavior.double.missing_half"); + return new DoubleBlockBehavior(block, half); + } + } +} 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 14e400675..308e0168e 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 @@ -37,14 +37,14 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { public void onPlace(Object thisBlock, Object[] args, Callable superMethod) { Object world = args[1]; Object blockPos = args[2]; - FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 2); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(world, blockPos, thisBlock, 2); } @Override public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) { Object world = args[updateShape$level]; Object blockPos = args[updateShape$blockPos]; - FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 2); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(world, blockPos, thisBlock, 2); return args[0]; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java index e608fc7b4..d4009daae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java @@ -83,7 +83,7 @@ public class GrassBlockBehavior extends BukkitBlockBehavior { @Override public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { Item item = context.getItem(); - if (item == null || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) + if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) return InteractionResult.PASS; BlockPos pos = context.getClickedPos(); BukkitBlockInWorld upper = (BukkitBlockInWorld) context.getLevel().getBlockAt(pos.x(), pos.y() + 1, pos.z()); @@ -107,12 +107,11 @@ public class GrassBlockBehavior extends BukkitBlockBehavior { return InteractionResult.SUCCESS; } - @SuppressWarnings("unchecked") @Override public void performBoneMeal(Object thisBlock, Object[] args) throws Exception { - Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.PLACED_FEATURE); + Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.PLACED_FEATURE); if (registry == null) return; - Optional holder = (Optional) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createPlacedFeatureKey(boneMealFeature())); + Optional holder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(registry, FeatureUtils.createPlacedFeatureKey(boneMealFeature())); if (holder.isEmpty()) { CraftEngine.instance().logger().warn("Placed feature not found: " + boneMealFeature()); return; 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 eb750aeba..21398bb83 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 @@ -59,7 +59,7 @@ public class LampBlockBehavior extends BukkitBlockBehavior { boolean lit = customState.get(this.litProperty); if (lit != FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(world, blockPos)) { if (lit) { - FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 4); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(world, blockPos, thisBlock, 4); } else { if (FastNMS.INSTANCE.method$CraftEventFactory$callRedstoneChange(world, blockPos, 0, 15).getNewCurrent() != 15) { return; 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 dec1efd68..7db9e3abb 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 @@ -66,7 +66,7 @@ public class LeavesBlockBehavior extends BukkitBlockBehavior { LeavesBlockBehavior behavior = optionalBehavior.get(); int distance = behavior.getDistanceAt(neighborState) + 1; if (distance != 1 || behavior.getDistance(optionalCustomState.get()) != distance) { - FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(world, blockPos, thisBlock, 1); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(world, blockPos, thisBlock, 1); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java index 2affa742b..9c9b02c65 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/NearLiquidBlockBehavior.java @@ -86,8 +86,8 @@ public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior { } protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) { - Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(world, belowPos); - Object fluidStateAbove = FastNMS.INSTANCE.method$Level$getFluidState(world, LocationUtils.above(belowPos)); + Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, belowPos); + Object fluidStateAbove = FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, LocationUtils.above(belowPos)); if (FastNMS.INSTANCE.method$FluidState$getType(fluidStateAbove) != MFluids.EMPTY) { return false; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java index 66581d144..e71780c7c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java @@ -65,8 +65,8 @@ public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior { return true; } } - Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(world, belowPos); - Object fluidStateAbove = FastNMS.INSTANCE.method$Level$getFluidState(world, LocationUtils.above(belowPos)); + Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, belowPos); + Object fluidStateAbove = FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, LocationUtils.above(belowPos)); if (FastNMS.INSTANCE.method$FluidState$getType(fluidStateAbove) != MFluids.EMPTY) { return false; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PressurePlateBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PressurePlateBlockBehavior.java index e2713c35b..9f3e513c7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PressurePlateBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PressurePlateBlockBehavior.java @@ -70,7 +70,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); world.playBlockSound(position, customState.settings().sounds().breakSound()); - FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId()); + FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId()); return MBlocks.AIR$defaultState; } return state; @@ -106,7 +106,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { this.checkPressed(args[3], args[1], args[2], state, signalForState, thisBlock); } else { // todo 为什么 - FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(args[1], args[2], thisBlock, this.pressedTime); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(args[1], args[2], thisBlock, this.pressedTime); } } @@ -150,7 +150,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { } if (isActive) { - FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(level, pos, thisBlock, this.pressedTime); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.pressedTime); } } @@ -182,6 +182,21 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { } } + @Override + public void onRemove(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object state = args[0]; + Object level = args[1]; + Object pos = args[2]; + Object newState = args[3]; + boolean movedByPiston = (boolean) args[4]; + if (!movedByPiston && !FastNMS.INSTANCE.method$BlockStateBase$is(state, FastNMS.INSTANCE.method$BlockState$getBlock(newState))) { + if (this.getSignalForState(state) > 0) { + this.updateNeighbours(level, pos, thisBlock); + } + superMethod.call(); + } + } + private void updateNeighbours(Object level, Object pos, Object thisBlock) { FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, pos, thisBlock); FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, LocationUtils.below(pos), thisBlock); 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 c9a069d2a..324c4752b 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 @@ -20,6 +20,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.ItemUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -79,17 +80,16 @@ 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.CONFIGURED_FEATURE); + Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.CONFIGURED_FEATURE); if (registry == null) return; - @SuppressWarnings("unchecked") - Optional holder = (Optional) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createConfiguredFeatureKey(treeFeature())); + Optional holder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(registry, FeatureUtils.createConfiguredFeatureKey(treeFeature())); if (holder.isEmpty()) { CraftEngine.instance().logger().warn("Configured feature not found: " + treeFeature()); return; } Object chunkGenerator = CoreReflections.method$ServerChunkCache$getGenerator.invoke(FastNMS.INSTANCE.method$ServerLevel$getChunkSource(world)); Object configuredFeature = CoreReflections.method$Holder$value.invoke(holder.get()); - Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(world, blockPos); + Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(world, blockPos); Object legacyState = CoreReflections.method$FluidState$createLegacyBlock.invoke(fluidState); FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, legacyState, UpdateOption.UPDATE_NONE.flags()); if ((boolean) CoreReflections.method$ConfiguredFeature$place.invoke(configuredFeature, world, chunkGenerator, randomSource, blockPos)) { @@ -148,7 +148,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior { @Override public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { Item item = context.getItem(); - if (item == null || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) + if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) return InteractionResult.PASS; boolean sendSwing = false; Object visualState = state.vanillaBlockState().handle(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java index 534c51339..3eaf4efcd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java @@ -16,10 +16,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.BlockBoundItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; -import net.momirealms.craftengine.core.util.Direction; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.inventory.ItemStack; @@ -41,7 +38,7 @@ public class SlabBlockBehavior extends BukkitBlockBehavior { public boolean canBeReplaced(BlockPlaceContext context, ImmutableBlockState state) { SlabType type = state.get(this.typeProperty); Item item = (Item) context.getItem(); - if (type == SlabType.DOUBLE || item == null) return false; + if (type == SlabType.DOUBLE || ItemUtils.isEmpty(item)) return false; Optional> itemInHand = item.getCustomItem(); if (itemInHand.isEmpty()) return false; CustomItem customItem = itemInHand.get(); @@ -69,7 +66,7 @@ public class SlabBlockBehavior extends BukkitBlockBehavior { blockState = blockState.with(super.waterloggedProperty, false); return blockState.with(this.typeProperty, SlabType.DOUBLE); } else { - Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos)); + Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos)); if (super.waterloggedProperty != null) state = state.with(super.waterloggedProperty, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER); Direction clickedFace = context.getClickedFace(); @@ -98,7 +95,7 @@ public class SlabBlockBehavior extends BukkitBlockBehavior { Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState); if (optionalCustomState.isEmpty()) return blockState; if (optionalCustomState.get().get(super.waterloggedProperty)) { - FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(VersionHelper.isOrAbove1_21_2() ? args[2] : args[3], VersionHelper.isOrAbove1_21_2() ? args[3] : args[4], MFluids.WATER, 5); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(VersionHelper.isOrAbove1_21_2() ? args[2] : args[3], VersionHelper.isOrAbove1_21_2() ? args[3] : args[4], MFluids.WATER, 5); } return blockState; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StackableBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StackableBlockBehavior.java index b367c804c..52fa4ba5c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StackableBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StackableBlockBehavior.java @@ -15,6 +15,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.sound.SoundData; +import net.momirealms.craftengine.core.util.ItemUtils; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -49,7 +50,7 @@ public class StackableBlockBehavior extends BukkitBlockBehavior { return InteractionResult.PASS; } Item item = (Item) context.getItem(); - if (item == null) { + if (ItemUtils.isEmpty(item)) { return InteractionResult.PASS; } if (!this.items.contains(item.id())) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StairsBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StairsBlockBehavior.java index fb2246d5e..64fc2c627 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StairsBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StairsBlockBehavior.java @@ -45,7 +45,7 @@ public class StairsBlockBehavior extends BukkitBlockBehavior { .with(this.facingProperty, context.getHorizontalDirection().toHorizontalDirection()) .with(this.halfProperty, clickedFace != Direction.DOWN && (clickedFace == Direction.UP || !(context.getClickLocation().y - clickedPos.y() > 0.5)) ? SingleBlockHalf.BOTTOM : SingleBlockHalf.TOP); if (super.waterloggedProperty != null) { - Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos)); + Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos)); blockState = blockState.with(this.waterloggedProperty, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER); } return blockState.with(this.shapeProperty, getStairsShape(blockState, context.getLevel().serverWorld(), clickedPos)); @@ -60,7 +60,7 @@ public class StairsBlockBehavior extends BukkitBlockBehavior { if (optionalCustomState.isEmpty()) return blockState; ImmutableBlockState customState = optionalCustomState.get(); if (super.waterloggedProperty != null && customState.get(this.waterloggedProperty)) { - FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5); } Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[1]); StairsShape stairsShape = getStairsShape(customState, level, LocationUtils.fromBlockPos(blockPos)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/TrapDoorBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/TrapDoorBlockBehavior.java index d559fd291..5f16405dd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/TrapDoorBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/TrapDoorBlockBehavior.java @@ -77,7 +77,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior { if (super.waterloggedProperty != null) { BlockStateUtils.getOptionalCustomBlockState(blockState).ifPresent(customState -> { if (customState.get(super.waterloggedProperty)) { - FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5); } }); } @@ -99,7 +99,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior { if (FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, clickedPos)) { state = state.with(this.poweredProperty, true).with(this.openProperty, true); } - if (this.waterloggedProperty != null && FastNMS.INSTANCE.method$FluidState$getType(FastNMS.INSTANCE.method$Level$getFluidState(level, clickedPos)) == MFluids.WATER) { + if (this.waterloggedProperty != null && FastNMS.INSTANCE.method$FluidState$getType(FastNMS.INSTANCE.method$BlockGetter$getFluidState(level, clickedPos)) == MFluids.WATER) { state = state.with(this.waterloggedProperty, true); } return state; @@ -197,7 +197,7 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior { FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, customState.with(this.poweredProperty, hasSignal).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS); if (this.waterloggedProperty != null && customState.get(this.waterloggedProperty)) { - FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(level, blockPos, MFluids.WATER, 5); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(level, blockPos, MFluids.WATER, 5); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java index 724bc0109..4542f71d2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java @@ -188,7 +188,7 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior { } @Override - public void onExplosionHit(Object thisBlock, Object[] args, Callable superMethod) { + public void onExplosionHit(Object thisBlock, Object[] args, Callable superMethod) throws Exception { for (AbstractBlockBehavior behavior : this.behaviors) { behavior.onExplosionHit(thisBlock, args, superMethod); } @@ -225,6 +225,13 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior { } } + @Override + public void onRemove(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.onRemove(thisBlock, args, superMethod); + } + } + @Override public int getSignal(Object thisBlock, Object[] args, Callable superMethod) { for (AbstractBlockBehavior behavior : this.behaviors) { @@ -256,4 +263,23 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior { } return false; } + + @Override + public Object playerWillDestroy(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object previous = args[0]; + for (AbstractBlockBehavior behavior : this.behaviors) { + Object processed = behavior.playerWillDestroy(thisBlock, args, superMethod); + if (processed != previous) { + return processed; + } + } + return previous; + } + + @Override + public void spawnAfterBreak(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.spawnAfterBreak(thisBlock, args, superMethod); + } + } } 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 ccc9c42cc..5fafae5db 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 @@ -137,6 +137,7 @@ public class BukkitFurniture implements Furniture { @NotNull public Object spawnPacket(Player player) { // TODO hasPermission might be slow, can we use a faster way in the future? + // TODO Make it based on conditions. So we can dynamically control which furniture should be sent to the player if (!this.minimized || player.hasPermission(FurnitureManager.FURNITURE_ADMIN_NODE)) { return this.cachedSpawnPacket; } else { 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 4970c0467..f108d5e2a 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 @@ -13,9 +13,6 @@ import net.momirealms.craftengine.core.entity.furniture.Furniture; import net.momirealms.craftengine.core.entity.furniture.FurnitureElement; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.data.FireworkExplosion; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.Material; @@ -72,7 +69,6 @@ public class BukkitFurnitureElement extends AbstractFurnitureElement { List cachedValues = new ArrayList<>(this.commonValues); Item item = BukkitItemManager.instance().createWrappedItem(item(), null); if (item == null) { - CraftEngine.instance().debug(() -> "Failed to create furniture element because item " + item() + " not found"); item = BukkitItemManager.instance().wrap(new ItemStack(Material.BARRIER)); } else { if (color != null) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java index 3defd743b..4e67ffd02 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/HappyGhastHitBox.java @@ -92,8 +92,8 @@ public class HappyGhastHitBox extends AbstractHitBox { double maxX = x + halfSize + offset.x(); double minY = y + offset.y(); double maxY = y + baseSize + offset.y(); - double minZ = z - halfSize + offset.z(); - double maxZ = z + halfSize + offset.z(); + double minZ = z - halfSize - offset.z(); + double maxZ = z + halfSize - offset.z(); return new AABB(minX, minY, minZ, maxX, maxY, maxZ); } @@ -119,9 +119,9 @@ public class HappyGhastHitBox extends AbstractHitBox { } double scale = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("scale", 1), "scale"); boolean hardCollision = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("hard-collision", true), "hard-collision"); - boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", false), "can-use-item-on"); - boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile"); - boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", false), "blocks-building"); + boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", true), "can-use-item-on"); + boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", true), "can-be-hit-by-projectile"); + boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building"); return new HappyGhastHitBox( HitBoxFactory.getSeats(arguments), MiscUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"), 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 1bdb20096..e6d28af4c 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 @@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; +import net.momirealms.craftengine.core.util.ItemUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.World; @@ -47,11 +48,22 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { @Override public void delayedInit() { Bukkit.getPluginManager().registerEvents(this, this.plugin.javaPlugin()); - for (World world : Bukkit.getWorlds()) { - List entities = world.getEntities(); - for (Entity entity : entities) { - if (entity instanceof Projectile projectile) { - handleProjectileLoad(projectile); + if (VersionHelper.isFolia()) { + for (World world : Bukkit.getWorlds()) { + List entities = world.getEntities(); + for (Entity entity : entities) { + if (entity instanceof Projectile projectile) { + projectile.getScheduler().run(this.plugin.javaPlugin(), (t) -> handleProjectileLoad(projectile), () -> {}); + } + } + } + } else { + for (World world : Bukkit.getWorlds()) { + List entities = world.getEntities(); + for (Entity entity : entities) { + if (entity instanceof Projectile projectile) { + handleProjectileLoad(projectile); + } } } } @@ -108,7 +120,7 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { return; } Item wrapped = this.plugin.itemManager().wrap(projectileItem); - if (wrapped == null) return; + if (ItemUtils.isEmpty(wrapped)) return; wrapped.getCustomItem().ifPresent(it -> { ProjectileMeta meta = it.settings().projectileMeta(); if (meta != null) { @@ -153,8 +165,13 @@ public class BukkitProjectileManager implements Listener, ProjectileManager { this.cachedServerEntity = serverEntity; } - if (!CoreReflections.clazz$AbstractArrow.isInstance(nmsEntity) || !this.checkInGround) { + if (!CoreReflections.clazz$AbstractArrow.isInstance(nmsEntity)) { updateProjectileUpdateInterval(1); + } else if (!this.checkInGround) { + updateProjectileUpdateInterval(1); + if (FastNMS.INSTANCE.field$Entity$wasTouchingWater(nmsEntity)) { + this.projectile.getWorld().spawnParticle(ParticleUtils.BUBBLE, this.projectile.getLocation(), 3, 0.1, 0.1, 0.1, 0); + } } else { boolean inGround = FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity); if (canSpawnParticle(nmsEntity, inGround)) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java index 06f4a5c9c..794c0e81a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/font/BukkitFontManager.java @@ -6,9 +6,10 @@ import io.papermc.paper.event.player.AsyncChatCommandDecorateEvent; import io.papermc.paper.event.player.AsyncChatDecorateEvent; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.paper.PaperReflections; import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.bukkit.util.InventoryUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; import net.momirealms.craftengine.core.font.*; import net.momirealms.craftengine.core.item.Item; @@ -130,15 +131,8 @@ public class BukkitFontManager extends AbstractFontManager implements Listener { return; } ItemStack result = event.getResult(); - if (result == null) return; - Player player; - try { - player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(VersionHelper.isOrAbove1_21() ? event.getView() : LegacyInventoryUtils.getView(event)); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to get inventory viewer", e); - return; - } - + if (ItemStackUtils.isEmpty(result)) return; + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); String renameText; if (VersionHelper.isOrAbove1_21_2()) { AnvilView anvilView = event.getView(); @@ -149,7 +143,7 @@ public class BukkitFontManager extends AbstractFontManager implements Listener { if (renameText == null || renameText.isEmpty()) return; Component itemName = Component.text(renameText); - EmojiComponentProcessResult replaceProcessResult = replaceComponentEmoji(itemName, plugin.adapt(player), renameText); + EmojiComponentProcessResult replaceProcessResult = replaceComponentEmoji(itemName, this.plugin.adapt(player), renameText); if (replaceProcessResult.changed()) { Item wrapped = this.plugin.itemManager().wrap(result); wrapped.customNameJson(AdventureHelper.componentToJson(replaceProcessResult.newText())); 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 40f031022..40954b670 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 @@ -8,8 +8,8 @@ import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; 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 net.momirealms.craftengine.core.util.UniqueKey; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; @@ -21,7 +21,7 @@ public class BukkitCustomItem extends AbstractCustomItem { private final Object item; private final Object clientItem; - public BukkitCustomItem(Holder id, Object item, Object clientItem, Key materialKey, Key clientBoundMaterialKey, + public BukkitCustomItem(UniqueKey id, Object item, Object clientItem, Key materialKey, Key clientBoundMaterialKey, List behaviors, List> modifiers, List> clientBoundModifiers, ItemSettings settings, @@ -64,7 +64,7 @@ public class BukkitCustomItem extends AbstractCustomItem { } public static class BuilderImpl implements Builder { - private Holder id; + private UniqueKey id; private Key itemKey; private final Object item; private Key clientBoundItemKey; @@ -81,7 +81,7 @@ public class BukkitCustomItem extends AbstractCustomItem { } @Override - public Builder id(Holder id) { + public Builder id(UniqueKey id) { this.id = id; return this; } @@ -149,6 +149,7 @@ public class BukkitCustomItem extends AbstractCustomItem { @Override public CustomItem build() { this.modifiers.addAll(this.settings.modifiers()); + this.clientBoundModifiers.addAll(this.settings.clientBoundModifiers()); 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 b291bccc7..2158202eb 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 @@ -1,5 +1,9 @@ package net.momirealms.craftengine.bukkit.item; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior; import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory; @@ -11,31 +15,30 @@ 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.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.modifier.IdModifier; +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; +import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceKey; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.plugin.logger.Debugger; +import net.momirealms.craftengine.core.util.*; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Optional; -import java.util.Set; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; public class BukkitItemManager extends AbstractItemManager { static { @@ -50,6 +53,10 @@ public class BukkitItemManager extends AbstractItemManager { private final DebugStickListener debugStickListener; private final ArmorEventListener armorEventListener; private final NetworkItemHandler networkItemHandler; + private final Object bedrockItemHolder; + private final Item emptyItem; + private final UniqueIdItem emptyUniqueItem; + private Set lastRegisteredPatterns = Set.of(); public BukkitItemManager(BukkitCraftEngine plugin) { super(plugin); @@ -61,6 +68,18 @@ public class BukkitItemManager extends AbstractItemManager { this.armorEventListener = new ArmorEventListener(); this.networkItemHandler = VersionHelper.isOrAbove1_20_5() ? new ModernNetworkItemHandler() : new LegacyNetworkItemHandler(); this.registerAllVanillaItems(); + this.bedrockItemHolder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(MBuiltInRegistries.ITEM, FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.ITEM, KeyUtils.toResourceLocation(Key.of("minecraft:bedrock")))).get();; + this.registerCustomTrimMaterial(); + this.loadLastRegisteredPatterns(); + + ItemStack emptyStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(CoreReflections.instance$ItemStack$EMPTY); + this.emptyItem = this.wrap(emptyStack); + this.emptyUniqueItem = new UniqueIdItem<>(UniqueKey.AIR, this.emptyItem); + } + + @Override + public UniqueIdItem uniqueEmptyItem() { + return this.emptyUniqueItem; } @Override @@ -70,6 +89,17 @@ public class BukkitItemManager extends AbstractItemManager { Bukkit.getPluginManager().registerEvents(this.armorEventListener, this.plugin.javaPlugin()); } + @Override + public Item decode(FriendlyByteBuf byteBuf) { + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(byteBuf); + return this.wrap(FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf)); + } + + @Override + public void encode(FriendlyByteBuf byteBuf, Item item) { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(FastNMS.INSTANCE.constructor$FriendlyByteBuf(byteBuf), item.getItem()); + } + @Override public NetworkItemHandler networkItemHandler() { return this.networkItemHandler; @@ -79,15 +109,25 @@ public class BukkitItemManager extends AbstractItemManager { return instance; } + @Override + public Item s2c(Item item, Player player) { + if (item.isEmpty()) return item; + return this.networkItemHandler.s2c(item, player).orElse(item); + } + + @Override + public Item c2s(Item item) { + if (item.isEmpty()) return item; + return this.networkItemHandler.c2s(item).orElse(item); + } + public Optional s2c(ItemStack itemStack, Player player) { try { Item wrapped = wrap(itemStack); - if (wrapped == null) return Optional.empty(); + if (wrapped.isEmpty()) return Optional.empty(); return this.networkItemHandler.s2c(wrapped, player).map(Item::getItem); } catch (Throwable e) { - if (Config.debug()) { - this.plugin.logger().warn("Failed to handle s2c items.", e); - } + Debugger.ITEM.warn(() -> "Failed to handle s2c items.", e); return Optional.empty(); } } @@ -95,12 +135,10 @@ public class BukkitItemManager extends AbstractItemManager { public Optional c2s(ItemStack itemStack) { try { Item wrapped = wrap(itemStack); - if (wrapped == null) return Optional.empty(); + if (wrapped.isEmpty()) return Optional.empty(); return this.networkItemHandler.c2s(wrapped).map(Item::getItem); } catch (Throwable e) { - if (Config.debug()) { - this.plugin.logger().warn("Failed to handle c2s items.", e); - } + Debugger.COMMON.warn(() -> "Failed to handle c2s items.", e); return Optional.empty(); } } @@ -116,7 +154,7 @@ public class BukkitItemManager extends AbstractItemManager { @Override public int fuelTime(ItemStack itemStack) { - if (ItemUtils.isEmpty(itemStack)) return 0; + if (ItemStackUtils.isEmpty(itemStack)) return 0; Optional> customItem = wrap(itemStack).getCustomItem(); return customItem.map(it -> it.settings().fuelTime()).orElse(0); } @@ -132,6 +170,127 @@ public class BukkitItemManager extends AbstractItemManager { HandlerList.unregisterAll(this.itemEventListener); HandlerList.unregisterAll(this.debugStickListener); HandlerList.unregisterAll(this.armorEventListener); + this.persistLastRegisteredPatterns(); + } + + @Override + protected void registerArmorTrimPattern(Collection equipments) { + if (equipments.isEmpty()) return; + this.lastRegisteredPatterns = new HashSet<>(equipments); + // 可能还没加载 + if (Config.sacrificedAssetId() != null) + this.lastRegisteredPatterns.add(Config.sacrificedAssetId()); + Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_PATTERN); + try { + CoreReflections.field$MappedRegistry$frozen.set(registry, false); + for (Key assetId : this.lastRegisteredPatterns) { + Object resourceLocation = KeyUtils.toResourceLocation(assetId); + Object previous = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation); + if (previous == null) { + Object trimPattern = createTrimPattern(assetId); + Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, trimPattern); + CoreReflections.method$Holder$Reference$bindValue.invoke(holder, trimPattern); + CoreReflections.field$Holder$Reference$tags.set(holder, Set.of()); + } + } + } catch (Exception e) { + this.plugin.logger().warn("Failed to register armor trim pattern.", e); + } finally { + try { + CoreReflections.field$MappedRegistry$frozen.set(registry, true); + } catch (ReflectiveOperationException ignored) { + } + } + } + + private void persistLastRegisteredPatterns() { + Path persistTrimPatternPath = this.plugin.dataFolderPath() + .resolve("cache") + .resolve("trim_patterns.json"); + try { + Files.createDirectories(persistTrimPatternPath.getParent()); + JsonObject json = new JsonObject(); + JsonArray jsonElements = new JsonArray(); + for (Key key : this.lastRegisteredPatterns) { + jsonElements.add(new JsonPrimitive(key.toString())); + } + json.add("patterns", jsonElements); + if (jsonElements.isEmpty()) { + if (Files.exists(persistTrimPatternPath)) { + Files.delete(persistTrimPatternPath); + } + } else { + GsonHelper.writeJsonFile(json, persistTrimPatternPath); + } + } catch (IOException e) { + this.plugin.logger().warn("Failed to persist registered trim patterns.", e); + } + } + + // 需要持久化存储上一次注册的新trim类型,如果注册晚了,加载世界可能导致一些物品损坏 + private void loadLastRegisteredPatterns() { + Path persistTrimPatternPath = this.plugin.dataFolderPath() + .resolve("cache") + .resolve("trim_patterns.json"); + if (Files.exists(persistTrimPatternPath) && Files.isRegularFile(persistTrimPatternPath)) { + try { + JsonObject cache = GsonHelper.readJsonFile(persistTrimPatternPath).getAsJsonObject(); + JsonArray patterns = cache.getAsJsonArray("patterns"); + Set trims = new HashSet<>(); + for (JsonElement element : patterns) { + if (element instanceof JsonPrimitive primitive) { + trims.add(Key.of(primitive.getAsString())); + } + } + this.registerArmorTrimPattern(trims); + this.lastRegisteredPatterns = trims; + } catch (IOException e) { + this.plugin.logger().warn("Failed to load registered trim patterns.", e); + } + } + } + + private void registerCustomTrimMaterial() { + Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_MATERIAL); + Object resourceLocation = KeyUtils.toResourceLocation(Key.of("minecraft", AbstractPackManager.NEW_TRIM_MATERIAL)); + Object previous = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation); + if (previous == null) { + try { + CoreReflections.field$MappedRegistry$frozen.set(registry, false); + Object trimMaterial = createTrimMaterial(); + Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, trimMaterial); + CoreReflections.method$Holder$Reference$bindValue.invoke(holder, trimMaterial); + CoreReflections.field$Holder$Reference$tags.set(holder, Set.of()); + } catch (Exception e) { + this.plugin.logger().warn("Failed to register trim material.", e); + } finally { + try { + CoreReflections.field$MappedRegistry$frozen.set(registry, true); + } catch (ReflectiveOperationException ignored) { + } + } + } + } + + private Object createTrimPattern(Key key) throws ReflectiveOperationException { + if (VersionHelper.isOrAbove1_21_5()) { + return CoreReflections.constructor$TrimPattern.newInstance(KeyUtils.toResourceLocation(key), CoreReflections.instance$Component$empty, false); + } else if (VersionHelper.isOrAbove1_20_2()) { + return CoreReflections.constructor$TrimPattern.newInstance(KeyUtils.toResourceLocation(key), this.bedrockItemHolder, CoreReflections.instance$Component$empty, false); + } else { + return CoreReflections.constructor$TrimPattern.newInstance(KeyUtils.toResourceLocation(key), this.bedrockItemHolder, CoreReflections.instance$Component$empty); + } + } + + private Object createTrimMaterial() throws ReflectiveOperationException { + if (VersionHelper.isOrAbove1_21_5()) { + Object assetGroup = CoreReflections.method$MaterialAssetGroup$create.invoke(null, "custom"); + return CoreReflections.constructor$TrimMaterial.newInstance(assetGroup, CoreReflections.instance$Component$empty); + } else if (VersionHelper.isOrAbove1_21_4()) { + return CoreReflections.constructor$TrimMaterial.newInstance("custom", this.bedrockItemHolder, Map.of(), CoreReflections.instance$Component$empty); + } else { + return CoreReflections.constructor$TrimMaterial.newInstance("custom", this.bedrockItemHolder, 0f, Map.of(), CoreReflections.instance$Component$empty); + } } @SuppressWarnings("deprecation") @@ -142,12 +301,16 @@ public class BukkitItemManager extends AbstractItemManager { @Override public ItemStack buildCustomItemStack(Key id, Player player) { - return Optional.ofNullable(customItems.get(id)).map(it -> it.buildItemStack(new ItemBuildContext(player, ContextHolder.EMPTY), 1)).orElse(null); + return Optional.ofNullable(this.customItems.get(id)).map(it -> it.buildItemStack(new ItemBuildContext(player, ContextHolder.EMPTY), 1)).orElse(null); } @Override public ItemStack buildItemStack(Key id, @Nullable Player player) { - return Optional.ofNullable(buildCustomItemStack(id, player)).orElseGet(() -> createVanillaItemStack(id)); + ItemStack customItem = buildCustomItemStack(id, player); + if (customItem != null) { + return customItem; + } + return createVanillaItemStack(id); } @Override @@ -155,31 +318,30 @@ public class BukkitItemManager extends AbstractItemManager { return Optional.ofNullable(customItems.get(id)).map(it -> it.buildItem(player)).orElse(null); } - private ItemStack createVanillaItemStack(Key id) { - NamespacedKey key = NamespacedKey.fromString(id.toString()); - if (key == null) { - this.plugin.logger().warn(id + " is not a valid namespaced key"); - return new ItemStack(Material.AIR); + @Override + public Item createWrappedItem(Key id, @Nullable Player player) { + CustomItem customItem = this.customItems.get(id); + if (customItem != null) { + return customItem.buildItem(player); } + ItemStack itemStack = this.createVanillaItemStack(id); + if (itemStack != null) { + return wrap(itemStack); + } + return null; + } + + private ItemStack createVanillaItemStack(Key id) { Object item = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, KeyUtils.toResourceLocation(id)); if (item == null) { - this.plugin.logger().warn(id + " is not a valid material"); - return new ItemStack(Material.AIR); + return null; } return FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.constructor$ItemStack(item, 1)); } @Override - public Item createWrappedItem(Key id, @Nullable Player player) { - return Optional.ofNullable(this.customItems.get(id)).map(it -> it.buildItem(player)).orElseGet(() -> { - ItemStack itemStack = createVanillaItemStack(id); - return wrap(itemStack); - }); - } - - @Override - public Item wrap(ItemStack itemStack) { - if (ItemUtils.isEmpty(itemStack)) return null; + public @NotNull Item wrap(ItemStack itemStack) { + if (itemStack == null) return this.emptyItem; return this.factory.wrap(itemStack); } @@ -197,7 +359,7 @@ public class BukkitItemManager extends AbstractItemManager { } @Override - protected CustomItem.Builder createPlatformItemBuilder(Holder id, Key materialId, Key clientBoundMaterialId) { + protected CustomItem.Builder createPlatformItemBuilder(UniqueKey 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) { @@ -220,14 +382,12 @@ public class BukkitItemManager extends AbstractItemManager { Key itemKey = KeyUtils.resourceLocationToKey(resourceLocation); if (itemKey.namespace().equals("minecraft")) { VANILLA_ITEMS.add(itemKey); - Holder.Reference holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(itemKey) - .orElseGet(() -> ((WritableRegistry) BuiltInRegistries.OPTIMIZED_ITEM_ID) - .register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), itemKey), itemKey)); - Object mcHolder = ((Optional) CoreReflections.method$Registry$getHolder1.invoke(MBuiltInRegistries.ITEM, CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.ITEM, resourceLocation))).get(); + UniqueKey uniqueKey = UniqueKey.create(itemKey); + Object mcHolder = FastNMS.INSTANCE.method$Registry$getHolderByResourceKey(MBuiltInRegistries.ITEM, FastNMS.INSTANCE.method$ResourceKey$create(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()); - VANILLA_ITEM_TAGS.computeIfAbsent(tagId, (key) -> new ArrayList<>()).add(holder); + VANILLA_ITEM_TAGS.computeIfAbsent(tagId, (key) -> new ArrayList<>()).add(uniqueKey); } } } @@ -235,4 +395,46 @@ public class BukkitItemManager extends AbstractItemManager { plugin.logger().warn("Failed to init vanilla items", e); } } + + // 1.20-1.21.4 template 不为空 + // 1.21.5+ pattern 不为空 + @Override + public Item applyTrim(Item base, Item addition, Item template, Key pattern) { + Optional optionalMaterial = FastNMS.INSTANCE.method$TrimMaterials$getFromIngredient(addition.getLiteralObject()); + Optional optionalPattern = VersionHelper.isOrAbove1_21_5() ? + FastNMS.INSTANCE.method$Registry$getHolderByResourceLocation(FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_PATTERN), KeyUtils.toResourceLocation(pattern)) : + FastNMS.INSTANCE.method$TrimPatterns$getFromTemplate(template.getLiteralObject()); + if (optionalMaterial.isPresent() && optionalPattern.isPresent()) { + Object armorTrim = FastNMS.INSTANCE.constructor$ArmorTrim(optionalMaterial.get(), optionalPattern.get()); + Object previousTrim; + if (VersionHelper.isOrAbove1_20_5()) { + previousTrim = base.getExactComponent(ComponentKeys.TRIM); + } else { + try { + previousTrim = VersionHelper.isOrAbove1_20_2() ? + ((Optional) CoreReflections.method$ArmorTrim$getTrim.invoke(null, FastNMS.INSTANCE.registryAccess(), base.getLiteralObject(), true)).orElse(null) : + ((Optional) CoreReflections.method$ArmorTrim$getTrim.invoke(null, FastNMS.INSTANCE.registryAccess(), base.getLiteralObject())).orElse(null); + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to get armor trim", e); + return this.emptyItem; + } + } + if (armorTrim.equals(previousTrim)) { + return this.emptyItem; + } + Item newItem = base.copyWithCount(1); + if (VersionHelper.isOrAbove1_20_5()) { + newItem.setExactComponent(ComponentKeys.TRIM, armorTrim); + } else { + try { + CoreReflections.method$ArmorTrim$setTrim.invoke(null, FastNMS.INSTANCE.registryAccess(), newItem.getLiteralObject(), armorTrim); + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to set armor trim", e); + return this.emptyItem; + } + } + return newItem; + } + return this.emptyItem; + } } 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 4414f8e54..680d5b8e5 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 @@ -8,7 +8,7 @@ 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.ItemUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.util.Key; @@ -22,12 +22,12 @@ public class ComponentItemWrapper implements ItemWrapper { private final Object handle; public ComponentItemWrapper(final ItemStack item) { - this.item = ItemUtils.ensureCraftItemStack(item); + this.item = ItemStackUtils.ensureCraftItemStack(item); this.handle = FastNMS.INSTANCE.field$CraftItemStack$handle(this.item); } public ComponentItemWrapper(final ItemStack item, int count) { - this.item = ItemUtils.ensureCraftItemStack(item); + this.item = ItemStackUtils.ensureCraftItemStack(item); this.item.setAmount(count); this.handle = FastNMS.INSTANCE.field$CraftItemStack$handle(this.item); } @@ -72,8 +72,18 @@ public class ComponentItemWrapper implements ItemWrapper { return getComponentInternal(type, MRegistryOps.NBT); } + @SuppressWarnings({"rawtypes", "unchecked"}) public Optional getSparrowNBTComponent(Object type) { - return getComponentInternal(type, MRegistryOps.SPARROW_NBT); + Object componentType = ensureDataComponentType(type); + Codec codec = FastNMS.INSTANCE.method$DataComponentType$codec(componentType); + try { + Object componentData = FastNMS.INSTANCE.method$ItemStack$getComponent(getLiteralObject(), componentType); + if (componentData == null) return Optional.empty(); + DataResult result = codec.encodeStart(MRegistryOps.SPARROW_NBT, componentData); + return result.result().map(Tag::copy); + } catch (Throwable t) { + throw new RuntimeException("Cannot read component " + type.toString(), t); + } } @SuppressWarnings({"rawtypes", "unchecked"}) 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 93c9cad48..fbb73a8cc 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 @@ -3,7 +3,7 @@ package net.momirealms.craftengine.bukkit.item; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps; -import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; @@ -13,7 +13,7 @@ public class LegacyItemWrapper implements ItemWrapper { private final ItemStack itemStack; public LegacyItemWrapper(ItemStack item) { - this.itemStack = ItemUtils.ensureCraftItemStack(item); + this.itemStack = ItemStackUtils.ensureCraftItemStack(item); this.nmsStack = FastNMS.INSTANCE.field$CraftItemStack$handle(this.itemStack); } @@ -72,6 +72,7 @@ public class LegacyItemWrapper implements ItemWrapper { getItem().setAmount(amount); } + @SuppressWarnings("DuplicatedCode") public Object getExactTag(Object... path) { Object compoundTag = FastNMS.INSTANCE.method$ItemStack$getTag(this.nmsStack); if (compoundTag == null) return null; 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 871bbcb32..6c4d94cf2 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 @@ -27,7 +27,7 @@ import java.util.Optional; import java.util.function.BiConsumer; @SuppressWarnings("DuplicatedCode") -public class LegacyNetworkItemHandler implements NetworkItemHandler { +public final class LegacyNetworkItemHandler implements NetworkItemHandler { @Override public Optional> c2s(Item wrapped) { @@ -45,7 +45,7 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler { return Optional.of(wrapped); } } - CompoundTag networkData = (CompoundTag) wrapped.getNBTTag(NETWORK_ITEM_TAG); + CompoundTag networkData = (CompoundTag) wrapped.getTag(NETWORK_ITEM_TAG); if (networkData == null) return Optional.empty(); wrapped.removeTag(NETWORK_ITEM_TAG); for (Map.Entry entry : networkData.entrySet()) { @@ -74,7 +74,7 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler { return new OtherItem(wrapped, hasDifferentMaterial).process(); } else { CompoundTag tag = new CompoundTag(); - Tag argumentTag = wrapped.getNBTTag(ArgumentModifier.ARGUMENTS_TAG); + Tag argumentTag = wrapped.getTag(ArgumentModifier.ARGUMENTS_TAG); ItemBuildContext context; if (argumentTag instanceof CompoundTag arguments) { ContextHolder.Builder builder = ContextHolder.builder(); @@ -87,6 +87,8 @@ public class LegacyNetworkItemHandler implements NetworkItemHandler { } for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { modifier.prepareNetworkItem(wrapped, context, tag); + } + for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { modifier.apply(wrapped, context); } if (Config.interceptItem()) { 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 f58ccad29..b94a64568 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 @@ -29,7 +29,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler> c2s(Item wrapped) { - Tag customData = wrapped.getNBTComponent(ComponentTypes.CUSTOM_DATA); + Tag customData = wrapped.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA); if (!(customData instanceof CompoundTag compoundTag)) return Optional.empty(); Optional> optionalCustomItem = wrapped.getCustomItem(); boolean hasDifferentMaterial = false; @@ -75,7 +75,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler modifier : customItem.clientBoundDataModifiers()) { modifier.prepareNetworkItem(wrapped, context, tag); + } + for (ItemDataModifier modifier : customItem.clientBoundDataModifiers()) { modifier.apply(wrapped, context); } if (Config.interceptItem()) { @@ -174,7 +176,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler item, Supplier tag) { - Tag nameTag = item.getNBTComponent(ComponentTypes.ITEM_NAME); + Tag nameTag = item.getSparrowNBTComponent(ComponentTypes.ITEM_NAME); if (nameTag == null) return false; String tagStr = nameTag.getAsString(); Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); @@ -187,7 +189,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler item, Supplier tag) { - Tag nameTag = item.getNBTComponent(ComponentTypes.CUSTOM_NAME); + Tag nameTag = item.getSparrowNBTComponent(ComponentTypes.CUSTOM_NAME); if (nameTag == null) return false; String tagStr = nameTag.getAsString(); Map tokens = CraftEngine.instance().fontManager().matchTags(tagStr); @@ -200,7 +202,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler item, Supplier tagSupplier) { - Tag loreTag = item.getNBTComponent(ComponentTypes.LORE); + Tag loreTag = item.getSparrowNBTComponent(ComponentTypes.LORE); boolean changed = false; if (!(loreTag instanceof ListTag listTag)) { return false; @@ -252,7 +254,7 @@ public final class ModernNetworkItemHandler implements NetworkItemHandler offHandItem = (Item) player.getItemInHand(InteractionHand.OFF_HAND); // is using a shield - if (context.getHand() == InteractionHand.MAIN_HAND && offHandItem != null && canBlockAttack(offHandItem) && !player.isSecondaryUseActive()) { + if (context.getHand() == InteractionHand.MAIN_HAND && !ItemUtils.isEmpty(offHandItem) && canBlockAttack(offHandItem) && !player.isSecondaryUseActive()) { return InteractionResult.PASS; } @@ -90,6 +91,8 @@ public class AxeItemBehavior extends ItemBehavior { } Item item = (Item) context.getItem(); + // 理论不可能出现 + if (ItemUtils.isEmpty(item)) return InteractionResult.FAIL; BlockPos pos = context.getClickedPos(); context.getLevel().playBlockSound(Vec3d.atCenterOf(pos), AXE_STRIP_SOUND, 1, 1); FastNMS.INSTANCE.method$LevelWriter$setBlock(context.getLevel().serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().handle(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompostableItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompostableItemBehavior.java index c29f1f265..9085e54bb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompostableItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompostableItemBehavior.java @@ -61,7 +61,7 @@ public class CompostableItemBehavior extends ItemBehavior { 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$scheduleBlockTick(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), blockOwner, 20); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), blockOwner, 20); } if (!context.getPlayer().canInstabuild()) { context.getItem().shrink(1); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java index ff545d711..d974d8924 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java @@ -128,6 +128,8 @@ public class FurnitureItemBehavior extends ItemBehavior { } Item item = context.getItem(); + // 不可能 + if (ItemUtils.isEmpty(item)) return InteractionResult.FAIL; BukkitFurniture bukkitFurniture = BukkitFurnitureManager.instance().place( furnitureLocation.clone(), customFurniture, 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 f5ad7bf9c..591369a9f 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 @@ -1,14 +1,19 @@ package net.momirealms.craftengine.bukkit.item.factory; import com.google.gson.JsonElement; +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.util.ItemTags; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.item.ItemFactory; +import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.ItemWrapper; import net.momirealms.craftengine.core.item.data.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.craftengine.core.util.UniqueKey; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; @@ -40,7 +45,7 @@ public abstract class BukkitItemFactory> extend case "1.21.4" -> { return new ComponentItemFactory1_21_4(plugin); } - case "1.21.5", "1.21.6", "1.22", "1.22.1" -> { + case "1.21.5", "1.21.6", "1.21.7", "1.22", "1.22.1" -> { return new ComponentItemFactory1_21_5(plugin); } default -> throw new IllegalStateException("Unsupported server version: " + plugin.serverVersion()); @@ -55,13 +60,14 @@ public abstract class BukkitItemFactory> extend @Override protected boolean isBlockItem(W item) { - // todo 这个 isBlockItem 他考虑组件了吗??? - return item.getItem().getType().isBlock(); + return CoreReflections.clazz$BlockItem.isInstance(FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject())); } @Override protected Key vanillaId(W item) { - return Key.of(item.getItem().getType().getKey().asString()); + Object i = FastNMS.INSTANCE.method$ItemStack$getItem(item.getLiteralObject()); + if (i == null) return ItemKeys.AIR; + return KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ITEM, i)); } @Override @@ -74,6 +80,11 @@ public abstract class BukkitItemFactory> extend return item.getItem(); } + @Override + protected UniqueKey recipeIngredientID(W item) { + return UniqueKey.create(id(item)); + } + @Override protected boolean is(W item, Key itemTag) { Object literalObject = item.getLiteralObject(); @@ -111,7 +122,12 @@ public abstract class BukkitItemFactory> extend } @Override - protected Tag getNBTComponent(W item, Object type) { + public Object getNBTComponent(W item, Object type) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + + @Override + protected Tag getSparrowNBTComponent(W item, Object type) { throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); } @@ -130,6 +146,11 @@ public abstract class BukkitItemFactory> extend throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); } + @Override + protected void setExactComponent(W item, Object type, Object value) { + throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); + } + @Override protected boolean hasComponent(W item, Object type) { throw new UnsupportedOperationException("This feature is only available on 1.20.5+"); 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 ba7ca035c..9abbd8a16 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 @@ -20,7 +20,10 @@ import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; public class ComponentItemFactory1_20_5 extends BukkitItemFactory { @@ -28,6 +31,11 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory trimMap = (Map) trim.get(); - return Optional.of(new Trim(trimMap.get("pattern"), trimMap.get("material"))); + return Optional.of(new Trim(Key.of(trimMap.get("pattern")), Key.of(trimMap.get("material")))); } @SuppressWarnings("unchecked") diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java index 254aeff5e..99263f9d8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_21_2.java @@ -2,9 +2,14 @@ package net.momirealms.craftengine.bukkit.item.factory; import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper; import net.momirealms.craftengine.bukkit.item.ComponentTypes; +import net.momirealms.craftengine.core.entity.EquipmentSlot; 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.craftengine.core.util.MiscUtils; +import java.util.Locale; +import java.util.Map; import java.util.Optional; public class ComponentItemFactory1_21_2 extends ComponentItemFactory1_21 { @@ -52,6 +57,18 @@ public class ComponentItemFactory1_21_2 extends ComponentItemFactory1_21 { @Override protected Optional equippable(ComponentItemWrapper item) { - throw new UnsupportedOperationException("Not implemented yet."); + Optional optionalData = item.getJavaComponent(ComponentTypes.EQUIPPABLE); + if (optionalData.isEmpty()) return Optional.empty(); + Map data = MiscUtils.castToMap(optionalData.get(), false); + String slot = data.get("slot").toString(); + return Optional.of(new EquipmentData( + EquipmentSlot.valueOf(slot.toUpperCase(Locale.ENGLISH)), + data.containsKey("asset_id") ? Key.of((String) data.get("asset_id")) : null, + (boolean) data.getOrDefault("dispensable", true), + (boolean) data.getOrDefault("swappable", true), + (boolean) data.getOrDefault("damage_on_hurt", true), + (boolean) data.getOrDefault("equip_on_interact", false), + data.containsKey("camera_overlay") ? Key.of((String) data.get("camera_overlay")) : null + )); } } \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java index 9d802d265..1d77a5ef4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java @@ -43,10 +43,15 @@ public class UniversalItemFactory extends BukkitItemFactory { } @Override - protected Tag getNBTTag(LegacyItemWrapper item, Object... path) { + protected Tag getTag(LegacyItemWrapper item, Object... path) { return item.getNBTTag(path); } + @Override + protected Object getExactTag(LegacyItemWrapper item, Object... path) { + return item.getExactTag(path); + } + @Override protected boolean hasTag(LegacyItemWrapper item, Object... path) { return item.hasTag(path); @@ -57,6 +62,11 @@ public class UniversalItemFactory extends BukkitItemFactory { return item.remove(path); } + @Override + protected boolean isEmpty(LegacyItemWrapper item) { + return item.getItem().isEmpty(); + } + @Override protected Optional customId(LegacyItemWrapper item) { Object id = item.getJavaTag(IdModifier.CRAFT_ENGINE_ID); @@ -258,8 +268,8 @@ public class UniversalItemFactory extends BukkitItemFactory { item.remove("Trim"); return; } - item.setTag(trim.material(), "Trim", "material"); - item.setTag(trim.pattern(), "Trim", "pattern"); + item.setTag(trim.material().asString(), "Trim", "material"); + item.setTag(trim.pattern().asString(), "Trim", "pattern"); } @Override @@ -299,7 +309,7 @@ public class UniversalItemFactory extends BukkitItemFactory { String material = item.getJavaTag("Trim", "material"); String pattern = item.getJavaTag("Trim", "pattern"); if (material == null || pattern == null) return Optional.empty(); - return Optional.of(new Trim(material, pattern)); + return Optional.of(new Trim(Key.of(material), Key.of(pattern))); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ArmorEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ArmorEventListener.java index 0b748e981..40604516d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ArmorEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ArmorEventListener.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.bukkit.item.listener; import net.momirealms.craftengine.bukkit.api.CraftEngineItems; -import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Material; import org.bukkit.entity.Horse; @@ -60,7 +60,7 @@ public class ArmorEventListener implements Listener { } else if (event.getClickedInventory() == horseInventory) { ItemStack itemInCursor = event.getCursor(); if (event.getAction() == InventoryAction.SWAP_WITH_CURSOR || event.getAction() == InventoryAction.PLACE_ALL || event.getAction() == InventoryAction.PLACE_ONE) { - if (!ItemUtils.isEmpty(itemInCursor) && CraftEngineItems.isCustomItem(itemInCursor)) { + if (!ItemStackUtils.isEmpty(itemInCursor) && CraftEngineItems.isCustomItem(itemInCursor)) { event.setCancelled(true); return; } @@ -69,13 +69,13 @@ public class ArmorEventListener implements Listener { int slot = event.getHotbarButton(); if (slot != -1) { ItemStack itemInHotBar = event.getWhoClicked().getInventory().getItem(slot); - if (!ItemUtils.isEmpty(itemInHotBar) && CraftEngineItems.isCustomItem(itemInHotBar)) { + if (!ItemStackUtils.isEmpty(itemInHotBar) && CraftEngineItems.isCustomItem(itemInHotBar)) { event.setCancelled(true); return; } } else { ItemStack offHand = event.getWhoClicked().getInventory().getItemInOffHand(); - if (!ItemUtils.isEmpty(offHand) && CraftEngineItems.isCustomItem(offHand)) { + if (!ItemStackUtils.isEmpty(offHand) && CraftEngineItems.isCustomItem(offHand)) { event.setCancelled(true); return; } @@ -92,7 +92,7 @@ public class ArmorEventListener implements Listener { } for (Map.Entry item : event.getNewItems().entrySet()) { if (item.getKey() == 0 || item.getKey() == 1) { - if (!ItemUtils.isEmpty(item.getValue()) && CraftEngineItems.isCustomItem(item.getValue())) { + if (!ItemStackUtils.isEmpty(item.getValue()) && CraftEngineItems.isCustomItem(item.getValue())) { event.setCancelled(true); return; } 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 2b698b749..26d9cb05a 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 @@ -9,6 +9,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkRefl import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; @@ -44,7 +45,7 @@ public class DebugStickListener implements Listener { Block clickedBlock = event.getClickedBlock(); if (clickedBlock == null) return; ItemStack itemInHand = event.getItem(); - if (itemInHand == null) return; + if (ItemStackUtils.isEmpty(itemInHand)) return; Material material = itemInHand.getType(); if (material != Material.DEBUG_STICK) return; Player bukkitPlayer = event.getPlayer(); 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 cad52ce04..b10dd7ad7 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 @@ -71,7 +71,7 @@ public class ItemEventListener implements Listener { InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; Item itemInHand = serverPlayer.getItemInHand(hand); - if (itemInHand == null) return; + if (ItemUtils.isEmpty(itemInHand)) return; Optional> optionalCustomItem = itemInHand.getCustomItem(); if (optionalCustomItem.isEmpty()) return; @@ -158,7 +158,7 @@ public class ItemEventListener implements Listener { .withParameter(DirectContextParameters.HAND, hand) .withParameter(DirectContextParameters.EVENT, dummy) .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(block.getLocation())) - .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, ItemUtils.isEmpty(itemInHand) ? null : itemInHand) ); if (action.isRightClick()) customBlock.execute(context, EventTrigger.RIGHT_CLICK); else customBlock.execute(context, EventTrigger.LEFT_CLICK); @@ -213,8 +213,8 @@ public class ItemEventListener implements Listener { } } - Optional> optionalCustomItem = itemInHand == null ? Optional.empty() : itemInHand.getCustomItem(); - boolean hasItem = itemInHand != null; + boolean hasItem = !itemInHand.isEmpty(); + Optional> optionalCustomItem = hasItem ? itemInHand.getCustomItem() : Optional.empty(); boolean hasCustomItem = optionalCustomItem.isPresent(); // interact block with items @@ -342,7 +342,7 @@ public class ItemEventListener implements Listener { InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; Item itemInHand = serverPlayer.getItemInHand(hand); // should never be null - if (itemInHand == null) return; + if (ItemUtils.isEmpty(itemInHand)) return; // todo 真的需要这个吗 if (cancelEventIfHasInteraction(event, serverPlayer, hand)) { @@ -384,7 +384,7 @@ public class ItemEventListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) public void onConsumeItem(PlayerItemConsumeEvent event) { ItemStack consumedItem = event.getItem(); - if (ItemUtils.isEmpty(consumedItem)) return; + if (ItemStackUtils.isEmpty(consumedItem)) return; Item wrapped = this.plugin.itemManager().wrap(consumedItem); Optional> optionalCustomItem = wrapped.getCustomItem(); if (optionalCustomItem.isEmpty()) { @@ -417,7 +417,7 @@ public class ItemEventListener implements Listener { if (VersionHelper.isOrAbove1_20_5()) return; if (!(event.getEntity() instanceof Player player)) return; ItemStack consumedItem = event.getItem(); - if (ItemUtils.isEmpty(consumedItem)) return; + if (ItemStackUtils.isEmpty(consumedItem)) return; Item wrapped = this.plugin.itemManager().wrap(consumedItem); Optional> optionalCustomItem = wrapped.getCustomItem(); if (optionalCustomItem.isEmpty()) { @@ -487,9 +487,9 @@ public class ItemEventListener implements Listener { ItemStack lazuli = inventory.getSecondary(); if (lazuli != null) return; ItemStack item = inventory.getItem(); - if (item == null) return; + if (ItemStackUtils.isEmpty(item)) return; Item wrapped = this.plugin.itemManager().wrap(item); - if (wrapped == null) return; + if (ItemUtils.isEmpty(wrapped)) return; Optional> optionalCustomItem = wrapped.getCustomItem(); if (optionalCustomItem.isEmpty()) return; BukkitCustomItem customItem = (BukkitCustomItem) optionalCustomItem.get(); 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 5c0a06144..ac76df75b 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 @@ -2,6 +2,9 @@ package net.momirealms.craftengine.bukkit.item.recipe; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import io.papermc.paper.potion.PotionMix; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.CloneableConstantItem; import net.momirealms.craftengine.bukkit.nms.FastNMS; @@ -13,18 +16,14 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOp import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.MaterialUtils; import net.momirealms.craftengine.bukkit.util.RecipeUtils; -import net.momirealms.craftengine.core.item.CustomItem; -import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.recipe.*; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.vanilla.*; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.HeptaFunction; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.*; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -135,11 +134,34 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } Object finalNmsRecipe = nmsRecipe; return () -> registerNMSSmithingRecipe(finalNmsRecipe); + } catch (InvalidRecipeIngredientException e) { + throw e; } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to convert smithing transform recipe", e); return null; } }); + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMITHING_TRIM, (BukkitRecipeConvertor>) (id, recipe) -> { + try { + Object nmsRecipe = createMinecraftSmithingTrimRecipe(recipe); + if (VersionHelper.isOrAbove1_21_2()) { + nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance( + CraftBukkitReflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())), nmsRecipe); + } else if (VersionHelper.isOrAbove1_20_2()) { + nmsRecipe = CoreReflections.constructor$RecipeHolder.newInstance(KeyUtils.toResourceLocation(id), nmsRecipe); + } else { + Object finalNmsRecipe0 = nmsRecipe; + return () -> registerNMSSmithingRecipe(finalNmsRecipe0); + } + Object finalNmsRecipe = nmsRecipe; + return () -> registerNMSSmithingRecipe(finalNmsRecipe); + } catch (InvalidRecipeIngredientException e) { + throw e; + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to convert smithing trim recipe", e); + return null; + } + }); // TODO DO NOT USE BUKKIT RECIPE AS BRIDGE IN FUTURE VERSIONS, WE SHOULD DIRECTLY CONSTRUCT THOSE NMS RECIPES MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SHAPED, (BukkitRecipeConvertor>) (id, recipe) -> { ShapedRecipe shapedRecipe = new ShapedRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY)); @@ -220,8 +242,8 @@ public class BukkitRecipeManager extends AbstractRecipeManager { }); MIXED_RECIPE_CONVERTORS.put(RecipeTypes.STONECUTTING, (BukkitRecipeConvertor>) (id, recipe) -> { List itemStacks = new ArrayList<>(); - for (Holder item : recipe.ingredient().items()) { - itemStacks.add(BukkitItemManager.instance().buildItemStack(item.value(), null)); + for (UniqueKey item : recipe.ingredient().items()) { + itemStacks.add(BukkitItemManager.instance().buildItemStack(item.key(), null)); } StonecuttingRecipe stonecuttingRecipe = new StonecuttingRecipe( new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), @@ -252,6 +274,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { private Object stolenFeatureFlagSet; // Some delayed tasks on main thread private final List delayedTasksOnMainThread = new ArrayList<>(); + private final Map brewingRecipes = new HashMap<>(); public BukkitRecipeManager(BukkitCraftEngine plugin) { instance = this; @@ -303,16 +326,16 @@ public class BukkitRecipeManager extends AbstractRecipeManager { @Override public void unload() { if (!Config.enableRecipeSystem()) return; - super.unload(); - if (VersionHelper.isOrAbove1_21_2()) { - this.plugin.scheduler().executeSync(() -> { - try { - CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to unregister recipes", e); - } - }); + // 安排卸载任务,这些任务会在load后执行。如果没有load说明服务器已经关闭了,那就不需要管卸载了。 + if (!Bukkit.isStopping()) { + for (Map.Entry> entry : this.byId.entrySet()) { + Key id = entry.getKey(); + if (isDataPackRecipe(id)) continue; + boolean isBrewingRecipe = entry.getValue() instanceof CustomBrewingRecipe; + this.delayedTasksOnMainThread.add(() -> this.unregisterPlatformRecipe(id, isBrewingRecipe)); + } } + super.unload(); } @Override @@ -325,6 +348,12 @@ public class BukkitRecipeManager extends AbstractRecipeManager { public void disable() { unload(); CE_RECIPE_2_NMS_HOLDER.clear(); + // 不是服务器关闭造成disable,那么需要把配方卸载干净 + if (!Bukkit.isStopping()) { + for (Runnable task : this.delayedTasksOnMainThread) { + task.run(); + } + } HandlerList.unregisterAll(this.recipeEventListener); if (this.crafterEventListener != null) { HandlerList.unregisterAll(this.crafterEventListener); @@ -332,19 +361,42 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } @Override - protected void unregisterPlatformRecipe(Key key) { - unregisterNMSRecipe(new NamespacedKey(key.namespace(), key.value())); + protected void unregisterPlatformRecipe(Key key, boolean isBrewingRecipe) { + if (isBrewingRecipe) { + Bukkit.getPotionBrewer().removePotionMix(new NamespacedKey(key.namespace(), key.value())); + } else { + unregisterNMSRecipe(new NamespacedKey(key.namespace(), key.value())); + } } @Override protected void registerPlatformRecipe(Key id, Recipe recipe) { - try { - Runnable converted = findNMSRecipeConvertor(recipe).convert(id, recipe); - if (converted != null) { - this.delayedTasksOnMainThread.add(converted); + if (recipe instanceof CustomBrewingRecipe brewingRecipe) { + PotionMix potionMix = new PotionMix(new NamespacedKey(id.namespace(), id.value()), + brewingRecipe.result(ItemBuildContext.EMPTY), + PotionMix.createPredicateChoice(container -> { + Item wrapped = this.plugin.itemManager().wrap(container); + return brewingRecipe.container().test(new UniqueIdItem<>(wrapped.recipeIngredientId(), wrapped)); + }), + PotionMix.createPredicateChoice(ingredient -> { + Item wrapped = this.plugin.itemManager().wrap(ingredient); + return brewingRecipe.ingredient().test(new UniqueIdItem<>(wrapped.recipeIngredientId(), wrapped)); + }) + ); + this.delayedTasksOnMainThread.add(() -> { + Bukkit.getPotionBrewer().addPotionMix(potionMix); + }); + } else { + try { + Runnable converted = findNMSRecipeConvertor(recipe).convert(id, recipe); + if (converted != null) { + this.delayedTasksOnMainThread.add(converted); + } + } catch (InvalidRecipeIngredientException e) { + throw new LocalizedResourceConfigException("warning.config.recipe.invalid_ingredient", e.ingredient()); + } catch (Exception e) { + this.plugin.logger().warn("Failed to convert recipe " + id, e); } - } catch (Exception e) { - this.plugin.logger().warn("Failed to convert recipe " + id, e); } } @@ -389,11 +441,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager { // continue; // } if (Config.disableAllVanillaRecipes()) { - this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id)); + this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id, false)); continue; } if (hasDisabledAny && Config.disabledVanillaRecipes().contains(id)) { - this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id)); + this.delayedTasksOnMainThread.add(() -> unregisterPlatformRecipe(id, false)); continue; } markAsDataPackRecipe(id); @@ -429,6 +481,10 @@ public class BukkitRecipeManager extends AbstractRecipeManager { VanillaSmithingTransformRecipe recipe = this.recipeReader.readSmithingTransform(jsonObject); handleDataPackSmithingTransform(id, recipe, (this.delayedTasksOnMainThread::add)); } + case "minecraft:smithing_trim" -> { + VanillaSmithingTrimRecipe recipe = this.recipeReader.readSmithingTrim(jsonObject); + handleDataPackSmithingTrim(id, recipe, (this.delayedTasksOnMainThread::add)); + } case "minecraft:stonecutting" -> { VanillaStoneCuttingRecipe recipe = this.recipeReader.readStoneCutting(jsonObject); handleDataPackStoneCuttingRecipe(id, recipe); @@ -494,13 +550,13 @@ public class BukkitRecipeManager extends AbstractRecipeManager { private void handleDataPackStoneCuttingRecipe(Key id, VanillaStoneCuttingRecipe recipe) { ItemStack result = createDataPackResultStack(recipe.result()); - Set> holders = new HashSet<>(); + Set holders = new HashSet<>(); for (String item : recipe.ingredient()) { if (item.charAt(0) == '#') { Key tag = Key.from(item.substring(1)); holders.addAll(this.plugin.itemManager().tagToItems(tag)); } else { - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); + holders.add(UniqueKey.create(Key.from(item))); } } CustomStoneCuttingRecipe ceRecipe = new CustomStoneCuttingRecipe<>( @@ -516,7 +572,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { boolean hasCustomItemInTag = false; List> ingredientList = new ArrayList<>(); for (List list : recipe.ingredients()) { - Set> holders = new HashSet<>(); + Set holders = new HashSet<>(); for (String item : list) { if (item.charAt(0) == '#') { Key tag = Key.of(item.substring(1)); @@ -527,7 +583,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } holders.addAll(plugin.itemManager().tagToItems(tag)); } else { - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); + holders.add(UniqueKey.create(Key.from(item))); } } ingredientList.add(Ingredient.of(holders)); @@ -552,7 +608,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { boolean hasCustomItemInTag = false; Map> ingredients = new HashMap<>(); for (Map.Entry> entry : recipe.ingredients().entrySet()) { - Set> holders = new HashSet<>(); + Set holders = new HashSet<>(); for (String item : entry.getValue()) { if (item.charAt(0) == '#') { Key tag = Key.from(item.substring(1)); @@ -563,7 +619,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } holders.addAll(plugin.itemManager().tagToItems(tag)); } else { - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); + holders.add(UniqueKey.create(Key.from(item))); } } ingredients.put(entry.getKey(), Ingredient.of(holders)); @@ -589,7 +645,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { Consumer callback) { NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); ItemStack result = createDataPackResultStack(recipe.result()); - Set> holders = new HashSet<>(); + Set holders = new HashSet<>(); boolean hasCustomItemInTag = readVanillaIngredients(false, recipe.ingredient(), holders::add); CustomCookingRecipe ceRecipe = constructor2.apply( id, recipe.category(), recipe.group(), @@ -612,11 +668,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager { ItemStack result = createDataPackResultStack(recipe.result()); boolean hasCustomItemInTag; - Set> additionHolders = new HashSet<>(); + Set additionHolders = new HashSet<>(); hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionHolders::add); - Set> templateHolders = new HashSet<>(); + Set templateHolders = new HashSet<>(); hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateHolders::add); - Set> baseHolders = new HashSet<>(); + Set baseHolders = new HashSet<>(); hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseHolders::add); CustomSmithingTransformRecipe ceRecipe = new CustomSmithingTransformRecipe<>( @@ -639,7 +695,36 @@ public class BukkitRecipeManager extends AbstractRecipeManager { this.registerInternalRecipe(id, ceRecipe); } - private boolean readVanillaIngredients(boolean hasCustomItemInTag, List ingredients, Consumer> holderConsumer) { + private void handleDataPackSmithingTrim(Key id, VanillaSmithingTrimRecipe recipe, Consumer callback) { + NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); + + boolean hasCustomItemInTag; + Set additionHolders = new HashSet<>(); + hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionHolders::add); + Set templateHolders = new HashSet<>(); + hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateHolders::add); + Set baseHolders = new HashSet<>(); + hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseHolders::add); + + CustomSmithingTrimRecipe ceRecipe = new CustomSmithingTrimRecipe<>( + id, + Ingredient.of(baseHolders), + Ingredient.of(templateHolders), + Ingredient.of(additionHolders), + Optional.ofNullable(recipe.pattern()).map(Key::of).orElse(null) + ); + + if (hasCustomItemInTag) { + Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); + callback.accept(() -> { + unregisterNMSRecipe(key); + converted.run(); + }); + } + this.registerInternalRecipe(id, ceRecipe); + } + + private boolean readVanillaIngredients(boolean hasCustomItemInTag, List ingredients, Consumer holderConsumer) { for (String item : ingredients) { if (item.charAt(0) == '#') { Key tag = Key.from(item.substring(1)); @@ -648,11 +733,11 @@ public class BukkitRecipeManager extends AbstractRecipeManager { hasCustomItemInTag = true; } } - for (Holder holder : this.plugin.itemManager().tagToItems(tag)) { + for (UniqueKey holder : this.plugin.itemManager().tagToItems(tag)) { holderConsumer.accept(holder); } } else { - holderConsumer.accept(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); + holderConsumer.accept(UniqueKey.create(Key.from(item))); } } return hasCustomItemInTag; @@ -695,8 +780,8 @@ public class BukkitRecipeManager extends AbstractRecipeManager { private static RecipeChoice ingredientToBukkitRecipeChoice(Ingredient ingredient) { Set materials = new HashSet<>(); - for (Holder holder : ingredient.items()) { - materials.add(getMaterialById(holder.value())); + for (UniqueKey holder : ingredient.items()) { + materials.add(getMaterialById(holder.key())); } return new RecipeChoice.MaterialChoice(new ArrayList<>(materials)); } @@ -707,15 +792,21 @@ public class BukkitRecipeManager extends AbstractRecipeManager { return material; } Optional> optionalItem = BukkitItemManager.instance().getCustomItem(key); - return optionalItem.map(itemStackCustomItem -> MaterialUtils.getMaterial(itemStackCustomItem.material())).orElse(null); + return optionalItem.map(itemStackCustomItem -> MaterialUtils.getMaterial(itemStackCustomItem.material())).orElseThrow(() -> new InvalidRecipeIngredientException(key.asString())); } - private static List getIngredientLooks(List> holders) { + 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); - Object nmsStack = FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack); - itemStacks.add(nmsStack); + for (UniqueKey holder : holders) { + Optional> buildableItem = BukkitItemManager.instance().getBuildableItem(holder.key()); + if (buildableItem.isPresent()) { + ItemStack itemStack = buildableItem.get().buildItemStack(ItemBuildContext.EMPTY, 1); + Object nmsStack = FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack); + itemStacks.add(nmsStack); + } else { + Item barrier = BukkitItemManager.instance().createWrappedItem(ItemKeys.BARRIER, null); + barrier.customNameJson(AdventureHelper.componentToJson(Component.text(holder.key().asString()).color(NamedTextColor.RED))); + } } return itemStacks; } @@ -887,4 +978,35 @@ public class BukkitRecipeManager extends AbstractRecipeManager { ); } } + + private static Object createMinecraftSmithingTrimRecipe(CustomSmithingTrimRecipe recipe) throws ReflectiveOperationException { + if (VersionHelper.isOrAbove1_21_5()) { + Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.TRIM_PATTERN); + return CoreReflections.constructor$SmithingTrimRecipe.newInstance( + toMinecraftIngredient(recipe.template()), + toMinecraftIngredient(recipe.base()), + toMinecraftIngredient(recipe.addition()), + FastNMS.INSTANCE.method$Registry$getHolderByResourceLocation(registry, KeyUtils.toResourceLocation(recipe.pattern())).orElseThrow(() -> new RuntimeException("Pattern " + recipe.pattern() + " doesn't exist.")) + ); + } else if (VersionHelper.isOrAbove1_21_2()) { + return CoreReflections.constructor$SmithingTrimRecipe.newInstance( + toOptionalMinecraftIngredient(recipe.template()), + toOptionalMinecraftIngredient(recipe.base()), + toOptionalMinecraftIngredient(recipe.addition()) + ); + } else if (VersionHelper.isOrAbove1_20_2()) { + return CoreReflections.constructor$SmithingTrimRecipe.newInstance( + toMinecraftIngredient(recipe.template()), + toMinecraftIngredient(recipe.base()), + toMinecraftIngredient(recipe.addition()) + ); + } else { + return CoreReflections.constructor$SmithingTrimRecipe.newInstance( + KeyUtils.toResourceLocation(recipe.id()), + toMinecraftIngredient(recipe.template()), + toMinecraftIngredient(recipe.base()), + toMinecraftIngredient(recipe.addition()) + ); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java index 2b2b9d383..5b5d2fd37 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java @@ -1,17 +1,15 @@ package net.momirealms.craftengine.bukkit.item.recipe; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemManager; -import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import org.bukkit.block.Crafter; import org.bukkit.event.EventHandler; @@ -23,10 +21,8 @@ import org.bukkit.inventory.ItemStack; import java.util.ArrayList; import java.util.List; -import java.util.Optional; public class CrafterEventListener implements Listener { - private static final OptimizedIDItem EMPTY = new OptimizedIDItem<>(null, null); private final ItemManager itemManager; private final BukkitRecipeManager recipeManager; private final BukkitCraftEngine plugin; @@ -56,40 +52,33 @@ public class CrafterEventListener implements Listener { Inventory inventory = crafter.getInventory(); ItemStack[] ingredients = inventory.getStorageContents(); - List> optimizedIDItems = new ArrayList<>(); + List> uniqueIdItems = new ArrayList<>(); for (ItemStack itemStack : ingredients) { - if (ItemUtils.isEmpty(itemStack)) { - optimizedIDItems.add(EMPTY); + if (ItemStackUtils.isEmpty(itemStack)) { + uniqueIdItems.add(this.itemManager.uniqueEmptyItem()); } else { Item wrappedItem = this.itemManager.wrap(itemStack); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - if (idHolder.isEmpty()) { - // an invalid item is used in recipe, we disallow it - event.setCancelled(true); - return; - } else { - optimizedIDItems.add(new OptimizedIDItem<>(idHolder.get(), itemStack)); - } + uniqueIdItems.add(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem)); } } CraftingInput input; if (ingredients.length == 9) { - input = CraftingInput.of(3, 3, optimizedIDItems); + input = CraftingInput.of(3, 3, uniqueIdItems); } else if (ingredients.length == 4) { - input = CraftingInput.of(2, 2, optimizedIDItems); + input = CraftingInput.of(2, 2, uniqueIdItems); } else { return; } Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input); if (ceRecipe != null) { - event.setResult(ceRecipe.result(ItemBuildContext.EMPTY)); + event.setResult(ceRecipe.assemble(input, ItemBuildContext.EMPTY)); return; } ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input); if (ceRecipe != null) { - event.setResult(ceRecipe.result(ItemBuildContext.EMPTY)); + event.setResult(ceRecipe.assemble(input, ItemBuildContext.EMPTY)); return; } // clear result if not met 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 3d3ab0837..2f1da0cb7 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 @@ -12,23 +12,21 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRecipeTypes; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.ComponentUtils; -import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.InventoryUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; import net.momirealms.craftengine.core.item.*; +import net.momirealms.craftengine.core.item.equipment.TrimBasedEquipment; import net.momirealms.craftengine.core.item.recipe.*; 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.item.setting.ItemEquipment; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.Pair; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.util.*; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Campfire; @@ -40,6 +38,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.*; import org.bukkit.event.inventory.*; +import org.bukkit.event.inventory.ClickType; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.*; import org.bukkit.inventory.view.AnvilView; @@ -51,7 +50,6 @@ import java.util.Optional; @SuppressWarnings("DuplicatedCode") public class RecipeEventListener implements Listener { - private static final OptimizedIDItem EMPTY = new OptimizedIDItem<>(null, null); private final ItemManager itemManager; private final BukkitRecipeManager recipeManager; private final BukkitCraftEngine plugin; @@ -74,13 +72,9 @@ public class RecipeEventListener implements Listener { if (clickedInventory == player.getInventory()) { if (event.getClick() == ClickType.SHIFT_LEFT || event.getClick() == ClickType.SHIFT_RIGHT) { ItemStack item = event.getCurrentItem(); - if (ItemUtils.isEmpty(item)) return; - if (fuelStack == null || fuelStack.getType() == Material.AIR) { - Item wrappedItem = BukkitItemManager.instance().wrap(item); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - if (idHolder.isEmpty()) return; - - SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), item)); + if (ItemStackUtils.isEmpty(item)) return; + if (ItemStackUtils.isEmpty(fuelStack)) { + SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(item)); Key recipeType; if (furnaceInventory.getType() == InventoryType.FURNACE) { recipeType = RecipeTypes.SMELTING; @@ -90,16 +84,16 @@ public class RecipeEventListener implements Listener { recipeType = RecipeTypes.SMOKING; } - Recipe ceRecipe = recipeManager.recipeByInput(recipeType, input); + Recipe ceRecipe = this.recipeManager.recipeByInput(recipeType, input); // The item is an ingredient, we should never consider it as fuel firstly if (ceRecipe != null) return; int fuelTime = this.itemManager.fuelTime(item); if (fuelTime == 0) { - if (ItemUtils.isCustomItem(item) && item.getType().isFuel()) { + if (ItemStackUtils.isCustomItem(item) && item.getType().isFuel()) { event.setCancelled(true); ItemStack smelting = furnaceInventory.getSmelting(); - if (ItemUtils.isEmpty(smelting)) { + if (ItemStackUtils.isEmpty(smelting)) { furnaceInventory.setSmelting(item.clone()); item.setAmount(0); } else if (smelting.isSimilar(item)) { @@ -160,11 +154,11 @@ public class RecipeEventListener implements Listener { } else { item = player.getInventory().getItem(hotBarSlot); } - if (item == null) return; + if (ItemStackUtils.isEmpty(item)) return; int fuelTime = this.plugin.itemManager().fuelTime(item); // only handle custom items if (fuelTime == 0) { - if (ItemUtils.isCustomItem(item) && item.getType().isFuel()) { + if (ItemStackUtils.isCustomItem(item) && item.getType().isFuel()) { event.setCancelled(true); } return; @@ -187,11 +181,11 @@ public class RecipeEventListener implements Listener { case LEFT, RIGHT -> { ItemStack itemOnCursor = event.getCursor(); // pick item - if (ItemUtils.isEmpty(itemOnCursor)) return; + if (ItemStackUtils.isEmpty(itemOnCursor)) return; int fuelTime = this.plugin.itemManager().fuelTime(itemOnCursor); // only handle custom items if (fuelTime == 0) { - if (ItemUtils.isCustomItem(itemOnCursor) && itemOnCursor.getType().isFuel()) { + if (ItemStackUtils.isCustomItem(itemOnCursor) && itemOnCursor.getType().isFuel()) { event.setCancelled(true); } return; @@ -344,7 +338,7 @@ public class RecipeEventListener implements Listener { } ItemStack itemStack = event.getItem(); - if (ItemUtils.isEmpty(itemStack)) return; + if (ItemStackUtils.isEmpty(itemStack)) return; try { @SuppressWarnings("unchecked") Optional optionalMCRecipe = FastNMS.INSTANCE.method$RecipeManager$getRecipeFor( @@ -357,12 +351,7 @@ public class RecipeEventListener implements Listener { if (optionalMCRecipe.isEmpty()) { return; } - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - if (idHolder.isEmpty()) { - return; - } - SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(itemStack)); CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setCancelled(true); @@ -387,14 +376,7 @@ public class RecipeEventListener implements Listener { } ItemStack itemStack = event.getSource(); - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - if (idHolder.isEmpty()) { - event.setTotalCookTime(Integer.MAX_VALUE); - return; - } - - SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(itemStack)); CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setTotalCookTime(Integer.MAX_VALUE); @@ -422,14 +404,7 @@ public class RecipeEventListener implements Listener { } ItemStack itemStack = event.getSource(); - Item wrappedItem = BukkitItemManager.instance().wrap(itemStack); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - if (idHolder.isEmpty()) { - event.setCancelled(true); - return; - } - - SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + SingleItemInput input = new SingleItemInput<>(getUniqueIdItem(itemStack)); CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setCancelled(true); @@ -444,87 +419,109 @@ public class RecipeEventListener implements Listener { public void onPrepareResult(PrepareResultEvent event) { // if (!ConfigManager.enableRecipeSystem()) return; if (event.getInventory() instanceof CartographyInventory cartographyInventory) { - if (ItemUtils.hasCustomItem(cartographyInventory.getStorageContents())) { + if (ItemStackUtils.hasCustomItem(cartographyInventory.getStorageContents())) { event.setResult(new ItemStack(Material.AIR)); } } } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onAnvilCombineItems(PrepareAnvilEvent event) { + public void onAnvilEvent(PrepareAnvilEvent event) { + preProcess(event); + processRepairable(event); + processRename(event); + } + + /* + 预处理会阻止一些不合理的原版材质造成的合并问题 + */ + private void preProcess(PrepareAnvilEvent event) { AnvilInventory inventory = event.getInventory(); ItemStack first = inventory.getFirstItem(); ItemStack second = inventory.getSecondItem(); if (first == null || second == null) return; Item wrappedFirst = BukkitItemManager.instance().wrap(first); - boolean firstCustom = wrappedFirst.isCustomItem(); + Optional> firstCustom = wrappedFirst.getCustomItem(); Item wrappedSecond = BukkitItemManager.instance().wrap(second); - boolean secondCustom = wrappedSecond.isCustomItem(); - // both are vanilla items - if (!firstCustom && !secondCustom) { + Optional> secondCustom = wrappedFirst.getCustomItem(); + // 两个都是原版物品 + if (firstCustom.isEmpty() && secondCustom.isEmpty()) { return; } - - // both of them are custom items - // if the second is an enchanted book, then apply it + // 如果第二个物品是附魔书,那么忽略 if (wrappedSecond.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { return; } - // one of them is vanilla item - if (!firstCustom || !secondCustom) { - if (second.canRepair(first)) return; // 这里需要考虑原版逻辑 - // block "vanilla + custom" recipes - event.setResult(null); - return; + // 被修的是自定义,材料不是自定义 + if (firstCustom.isPresent() && secondCustom.isEmpty()) { + if (firstCustom.get().settings().respectRepairableComponent()) { + if (second.canRepair(first)) return; // 尊重原版的repairable + } else { + event.setResult(null); + return; + } } - // not the same item + // 被修的是原版,材料是自定义 + if (firstCustom.isEmpty() && secondCustom.isPresent()) { + if (secondCustom.get().settings().respectRepairableComponent()) { + if (second.canRepair(first)) return; + } else { + event.setResult(null); + return; + } + } + + // 如果两个物品id不同,不能合并 if (!wrappedFirst.customId().equals(wrappedSecond.customId())) { event.setResult(null); return; } - // can not repair - wrappedFirst.getCustomItem().ifPresent(it -> { + // 如果禁止在铁砧使用两个相同物品修复 + firstCustom.ifPresent(it -> { if (!it.settings().canRepair()) { event.setResult(null); } }); } + /* + 处理item settings中repair item属性。如果修补材料不是自定义物品,则不会参与后续逻辑。 + 这会忽略preprocess里event.setResult(null); + */ @SuppressWarnings("UnstableApiUsage") - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOW) - public void onAnvilRepairItems(PrepareAnvilEvent event) { + private void processRepairable(PrepareAnvilEvent event) { AnvilInventory inventory = event.getInventory(); ItemStack first = inventory.getFirstItem(); ItemStack second = inventory.getSecondItem(); - if (first == null || second == null) return; + if (ItemStackUtils.isEmpty(first) || ItemStackUtils.isEmpty(second)) return; Item wrappedSecond = BukkitItemManager.instance().wrap(second); - // if the second slot is not a custom item, ignore it - Optional> customItemOptional = plugin.itemManager().getCustomItem(wrappedSecond.id()); + // 如果材料不是自定义的,那么忽略 + Optional> customItemOptional = this.plugin.itemManager().getCustomItem(wrappedSecond.id()); if (customItemOptional.isEmpty()) { return; } CustomItem customItem = customItemOptional.get(); List repairItems = customItem.settings().repairItems(); - // if the second slot is not a repair item, ignore it + // 如果材料不支持修复物品,则忽略 if (repairItems.isEmpty()) { return; } + // 后续均为修复逻辑 Item wrappedFirst = BukkitItemManager.instance().wrap(first.clone()); - int maxDamage = wrappedFirst.maxDamage(); int damage = wrappedFirst.damage().orElse(0); - // not a repairable item + // 物品无damage属性 if (damage == 0 || maxDamage == 0) return; Key firstId = wrappedFirst.id(); Optional> optionalCustomTool = wrappedFirst.getCustomItem(); - // can not repair + // 物品无法被修复 if (optionalCustomTool.isPresent() && !optionalCustomTool.get().settings().canRepair()) { return; } @@ -549,7 +546,7 @@ public class RecipeEventListener implements Listener { } } - // no repair item matching + // 找不到匹配的修复 if (repairItem == null) { return; } @@ -566,7 +563,7 @@ public class RecipeEventListener implements Listener { String renameText; int maxRepairCost; //int previousCost; - if (VersionHelper.isOrAbove1_21_2()) { + if (VersionHelper.isOrAbove1_21()) { AnvilView anvilView = event.getView(); renameText = anvilView.getRenameText(); maxRepairCost = anvilView.getMaximumRepairCost(); @@ -623,13 +620,7 @@ public class RecipeEventListener implements Listener { LegacyInventoryUtils.setRepairCostAmount(inventory, actualConsumedAmount); } - Player player; - try { - player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(VersionHelper.isOrAbove1_21() ? event.getView() : LegacyInventoryUtils.getView(event)); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to get inventory viewer", e); - return; - } + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); if (finalCost >= maxRepairCost && !plugin.adapt(player).canInstabuild()) { hasResult = false; @@ -647,12 +638,14 @@ public class RecipeEventListener implements Listener { } } + /* + 如果物品不可被重命名,则在最后处理。 + */ @SuppressWarnings("UnstableApiUsage") - @EventHandler(ignoreCancelled = true, priority = EventPriority.NORMAL) - public void onAnvilRenameItem(PrepareAnvilEvent event) { + private void processRename(PrepareAnvilEvent event) { AnvilInventory inventory = event.getInventory(); ItemStack first = inventory.getFirstItem(); - if (ItemUtils.isEmpty(first)) { + if (ItemStackUtils.isEmpty(first)) { return; } if (event.getResult() == null) { @@ -662,7 +655,7 @@ public class RecipeEventListener implements Listener { wrappedFirst.getCustomItem().ifPresent(item -> { if (!item.settings().renameable()) { String renameText; - if (VersionHelper.isOrAbove1_21_2()) { + if (VersionHelper.isOrAbove1_21()) { AnvilView anvilView = event.getView(); renameText = anvilView.getRenameText(); } else { @@ -695,7 +688,7 @@ public class RecipeEventListener implements Listener { if (!(recipe instanceof ComplexRecipe complexRecipe)) return; CraftingInventory inventory = event.getInventory(); - boolean hasCustomItem = ItemUtils.hasCustomItem(inventory.getMatrix()); + boolean hasCustomItem = ItemStackUtils.hasCustomItem(inventory.getMatrix()); if (!hasCustomItem) { return; } @@ -733,13 +726,7 @@ public class RecipeEventListener implements Listener { return; } - Player player; - try { - player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView()); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to get inventory viewer", e); - return; - } + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); Optional> customItemOptional = plugin.itemManager().getCustomItem(left.id()); if (customItemOptional.isEmpty()) { @@ -809,10 +796,10 @@ public class RecipeEventListener implements Listener { boolean hasReplacement = false; for (int i = 0; i < usedItems.length; i++) { ItemStack usedItem = usedItems[i]; - if (ItemUtils.isEmpty(usedItem)) continue; + if (ItemStackUtils.isEmpty(usedItem)) continue; if (usedItem.getAmount() != 1) continue; Item wrapped = BukkitItemManager.instance().wrap(usedItem); - if (wrapped == null) continue; + if (ItemUtils.isEmpty(wrapped)) continue; Optional> optionalCustomItem = wrapped.getCustomItem(); if (optionalCustomItem.isPresent()) { CustomItem customItem = optionalCustomItem.get(); @@ -861,46 +848,28 @@ public class RecipeEventListener implements Listener { CraftingInventory inventory = event.getInventory(); ItemStack[] ingredients = inventory.getMatrix(); - List> optimizedIDItems = new ArrayList<>(); + List> uniqueIdItems = new ArrayList<>(); for (ItemStack itemStack : ingredients) { - if (ItemUtils.isEmpty(itemStack)) { - optimizedIDItems.add(EMPTY); - } else { - Item wrappedItem = this.itemManager.wrap(itemStack); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - if (idHolder.isEmpty()) { - // an invalid item is used in recipe, we disallow it - inventory.setResult(null); - return; - } else { - optimizedIDItems.add(new OptimizedIDItem<>(idHolder.get(), itemStack)); - } - } + uniqueIdItems.add(getUniqueIdItem(itemStack)); } CraftingInput input; if (ingredients.length == 9) { - input = CraftingInput.of(3, 3, optimizedIDItems); + input = CraftingInput.of(3, 3, uniqueIdItems); } else if (ingredients.length == 4) { - input = CraftingInput.of(2, 2, optimizedIDItems); + input = CraftingInput.of(2, 2, uniqueIdItems); } else { return; } - Player player; - try { - player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView()); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to get inventory viewer", e); - return; - } + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); BukkitServerPlayer serverPlayer = this.plugin.adapt(player); Key lastRecipe = serverPlayer.lastUsedRecipe(); Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input, lastRecipe); if (ceRecipe != null) { - inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); + inventory.setResult(ceRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); serverPlayer.setLastUsedRecipe(ceRecipe.id()); if (!ceRecipe.id().equals(recipeId)) { correctCraftingRecipeUsed(inventory, ceRecipe); @@ -909,7 +878,7 @@ public class RecipeEventListener implements Listener { } ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input, lastRecipe); if (ceRecipe != null) { - inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); + inventory.setResult(ceRecipe.assemble(input, new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); serverPlayer.setLastUsedRecipe(ceRecipe.id()); if (!ceRecipe.id().equals(recipeId)) { correctCraftingRecipeUsed(inventory, ceRecipe); @@ -933,6 +902,54 @@ public class RecipeEventListener implements Listener { } } + @EventHandler(ignoreCancelled = true) + public void onSmithingTrim(PrepareSmithingEvent event) { + SmithingInventory inventory = event.getInventory(); + if (!(inventory.getRecipe() instanceof SmithingTrimRecipe recipe)) return; + + ItemStack equipment = inventory.getInputEquipment(); + if (!ItemStackUtils.isEmpty(equipment)) { + Item wrappedEquipment = this.itemManager.wrap(equipment); + Optional> optionalCustomItem = wrappedEquipment.getCustomItem(); + if (optionalCustomItem.isPresent()) { + CustomItem customItem = optionalCustomItem.get(); + ItemEquipment itemEquipmentSettings = customItem.settings().equipment(); + if (itemEquipmentSettings != null && itemEquipmentSettings.equipment() instanceof TrimBasedEquipment) { + // 不允许trim类型的盔甲再次被使用trim + event.setResult(null); + return; + } + } + } + + Key recipeId = Key.of(recipe.getKey().namespace(), recipe.getKey().value()); + boolean isCustom = this.recipeManager.isCustomRecipe(recipeId); + // Maybe it's recipe from other plugins, then we ignore it + if (!isCustom) { + return; + } + + SmithingInput input = new SmithingInput<>( + getUniqueIdItem(inventory.getInputEquipment()), + getUniqueIdItem(inventory.getInputTemplate()), + getUniqueIdItem(inventory.getInputMineral()) + ); + + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SMITHING_TRIM, input); + if (ceRecipe == null) { + event.setResult(null); + return; + } + + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); + CustomSmithingTrimRecipe trimRecipe = (CustomSmithingTrimRecipe) ceRecipe; + ItemStack result = trimRecipe.assemble(input, new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); + event.setResult(result); + if (!ceRecipe.id().equals(recipeId)) { + correctSmithingRecipeUsed(inventory, ceRecipe); + } + } + @EventHandler(ignoreCancelled = true) public void onSmithingTransform(PrepareSmithingEvent event) { if (!Config.enableRecipeSystem()) return; @@ -951,9 +968,9 @@ public class RecipeEventListener implements Listener { ItemStack addition = inventory.getInputMineral(); SmithingInput input = new SmithingInput<>( - getOptimizedIDItem(base), - getOptimizedIDItem(template), - getOptimizedIDItem(addition) + getUniqueIdItem(base), + getUniqueIdItem(template), + getUniqueIdItem(addition) ); Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SMITHING_TRANSFORM, input); @@ -962,16 +979,10 @@ public class RecipeEventListener implements Listener { return; } - Player player; - try { - player = (Player) CraftBukkitReflections.method$InventoryView$getPlayer.invoke(event.getView()); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to get inventory viewer", e); - return; - } + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); CustomSmithingTransformRecipe transformRecipe = (CustomSmithingTransformRecipe) ceRecipe; - ItemStack processed = transformRecipe.assemble(new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY), this.itemManager.wrap(base)); + ItemStack processed = transformRecipe.assemble(input, new ItemBuildContext(this.plugin.adapt(player), ContextHolder.EMPTY)); event.setResult(processed); if (!ceRecipe.id().equals(recipeId)) { correctSmithingRecipeUsed(inventory, ceRecipe); @@ -991,13 +1002,12 @@ public class RecipeEventListener implements Listener { } } - private OptimizedIDItem getOptimizedIDItem(@Nullable ItemStack itemStack) { - if (ItemUtils.isEmpty(itemStack)) { - return EMPTY; + private UniqueIdItem getUniqueIdItem(@Nullable ItemStack itemStack) { + if (ItemStackUtils.isEmpty(itemStack)) { + return this.itemManager.uniqueEmptyItem(); } else { Item wrappedItem = this.itemManager.wrap(itemStack); - Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); - return idHolder.map(keyReference -> new OptimizedIDItem<>(keyReference, itemStack)).orElse(EMPTY); + return new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index 14018080b..3aeeb074b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -54,6 +54,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme HandlerList.unregisterAll(this); } + @SuppressWarnings("UnstableApiUsage") @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onEntityDeath(EntityDeathEvent event) { Entity entity = event.getEntity(); @@ -90,7 +91,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme } public class VanillaLootParser implements ConfigParser { - public static final String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot", "loots", "loot"}; + public static final String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot", "vanilla_loots", "vanilla_loot"}; @Override public int loadingSequence() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java index fb69e797d..7ae11cc4f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java @@ -5,13 +5,11 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.command.feature.ReloadCommand; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.bukkit.util.EventUtils; import net.momirealms.craftengine.bukkit.util.ResourcePackUtils; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; -import net.momirealms.craftengine.core.pack.host.impl.NoneHost; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.VersionHelper; @@ -25,11 +23,9 @@ import org.bukkit.event.player.PlayerJoinEvent; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.UUID; import java.util.concurrent.CompletableFuture; public class BukkitPackManager extends AbstractPackManager implements Listener { - public static final String FAKE_URL = "https://127.0.0.1:65536"; private final BukkitCraftEngine plugin; public BukkitPackManager(BukkitCraftEngine plugin) { @@ -58,25 +54,6 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { public void load() { if (ReloadCommand.RELOAD_PACK_FLAG || CraftEngine.instance().isInitializing()) { super.load(); - if (Config.sendPackOnJoin() && VersionHelper.isOrAbove1_20_2() && !(resourcePackHost() instanceof NoneHost)) { - this.modifyServerSettings(); - } - } - } - - public void modifyServerSettings() { - try { - Object settings = CoreReflections.field$DedicatedServer$settings.get(CoreReflections.method$MinecraftServer$getServer.invoke(null)); - Object properties = CoreReflections.field$DedicatedServerSettings$properties.get(settings); - Object info; - if (VersionHelper.isOrAbove1_20_3()) { - info = CoreReflections.constructor$ServerResourcePackInfo.newInstance(new UUID(0, 0), FAKE_URL, "", Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt())); - } else { - info = CoreReflections.constructor$ServerResourcePackInfo.newInstance(FAKE_URL, "", Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt())); - } - CoreReflections.field$DedicatedServerProperties$serverResourcePackInfo.set(properties, Optional.of(info)); - } catch (Exception e) { - this.plugin.logger().warn("Failed to update resource pack settings", 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 5a84515de..6cdb33ec7 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 @@ -138,6 +138,7 @@ public class BukkitCraftEngine extends CraftEngine { super.onPluginLoad(); super.blockManager.init(); super.networkManager = new BukkitNetworkManager(this); + super.itemManager = new BukkitItemManager(this); this.successfullyLoaded = true; super.compatibilityManager().onLoad(); } @@ -182,7 +183,6 @@ public class BukkitCraftEngine extends CraftEngine { PacketConsumers.initEntities(RegistryUtils.currentEntityTypeRegistrySize()); super.packManager = new BukkitPackManager(this); super.senderFactory = new BukkitSenderFactory(this); - super.itemManager = new BukkitItemManager(this); super.recipeManager = new BukkitRecipeManager(this); super.commandManager = new BukkitCommandManager(this); super.itemBrowserManager = new ItemBrowserManagerImpl(this); @@ -270,7 +270,7 @@ public class BukkitCraftEngine extends CraftEngine { @Override public String serverVersion() { - return Bukkit.getServer().getBukkitVersion().split("-")[0]; + return VersionHelper.MINECRAFT_VERSION.version(); } @Override 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 798b1ea17..e1055644a 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 @@ -4,7 +4,6 @@ import com.google.gson.JsonElement; 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 net.momirealms.sparrow.nbt.CompoundTag; @@ -28,7 +27,6 @@ public class BukkitPlatform implements Platform { 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.type.snbt.invalid_syntax", e, nbt); } } @@ -45,7 +43,6 @@ public class BukkitPlatform implements Platform { CompoundTag map = (CompoundTag) MRegistryOps.NBT.convertTo(MRegistryOps.SPARROW_NBT, tag); return map.get("root"); } catch (CommandSyntaxException e) { - CraftEngine.instance().debug(e::getMessage); throw new LocalizedResourceConfigException("warning.config.type.snbt.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 ff38f3b8d..008bb53b8 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 @@ -41,6 +41,7 @@ public class BukkitCommandManager extends AbstractCommandManager new DebugGetBlockInternalIdCommand(this, plugin), new DebugAppearanceStateUsageCommand(this, plugin), new DebugClearCooldownCommand(this, plugin), + new DebugEntityIdCommand(this, plugin), new DebugRealStateUsageCommand(this, plugin), new DebugItemDataCommand(this, plugin), new DebugSetBlockCommand(this, plugin), diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugEntityIdCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugEntityIdCommand.java new file mode 100644 index 000000000..2513f665e --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugEntityIdCommand.java @@ -0,0 +1,42 @@ +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.World; +import org.bukkit.command.CommandSender; +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 DebugEntityIdCommand extends BukkitCommandFeature { + + public DebugEntityIdCommand(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"); + Object entityLookup = FastNMS.INSTANCE.method$ServerLevel$getEntityLookup(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world)); + Object entity = FastNMS.INSTANCE.method$EntityLookup$get(entityLookup, entityId); + if (entity == null) { + context.sender().sendMessage("entity not found"); + return; + } + context.sender().sendMessage(entity.toString()); + }); + } + + @Override + public String getFeatureID() { + return "debug_entity_id"; + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugItemDataCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugItemDataCommand.java index 54f936a46..861c01eb5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugItemDataCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugItemDataCommand.java @@ -3,7 +3,7 @@ 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.bukkit.plugin.reflection.minecraft.MRegistryOps; -import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.util.AdventureHelper; @@ -26,7 +26,7 @@ public class DebugItemDataCommand extends BukkitCommandFeature { .senderType(Player.class) .handler(context -> { ItemStack itemInHand = context.sender().getInventory().getItemInMainHand(); - if (ItemUtils.isEmpty(itemInHand)) { + if (ItemStackUtils.isEmpty(itemInHand)) { return; } Map readableMap = toMap(itemInHand); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java index 26e28808b..9425e7a3c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java @@ -30,7 +30,7 @@ public class SearchUsagePlayerCommand extends BukkitCommandFeature item = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); - if (item == null) { + if (item.isEmpty()) { handleFeedback(context, MessageConstants.COMMAND_SEARCH_USAGE_NO_ITEM); return; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitClick.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitClick.java index f301d2a91..2615b765c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitClick.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitClick.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.gui; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.util.ItemUtils; +import net.momirealms.craftengine.bukkit.util.ItemStackUtils; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.gui.Click; @@ -71,7 +71,7 @@ public class BukkitClick implements Click { @Override public Item itemOnCursor() { ItemStack itemStack = this.event.getCursor(); - if (ItemUtils.isEmpty(itemStack)) return null; + if (ItemStackUtils.isEmpty(itemStack)) return null; return BukkitItemManager.instance().wrap(itemStack); } 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 45e4d41cc..83b94ad9f 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 @@ -148,7 +148,7 @@ public final class BlockGenerator { // onExplosionHit 1.21+ .method(ElementMatchers.returns(void.class) .and(ElementMatchers.takesArgument(0, CoreReflections.clazz$BlockState)) - .and(ElementMatchers.takesArgument(1, CoreReflections.clazz$ServerLevel)) + .and(ElementMatchers.takesArgument(1, VersionHelper.isOrAbove1_21_2() ? CoreReflections.clazz$ServerLevel : CoreReflections.clazz$Level)) .and(ElementMatchers.takesArgument(2, CoreReflections.clazz$BlockPos)) .and(ElementMatchers.takesArgument(3, CoreReflections.clazz$Explosion)) .and(ElementMatchers.takesArgument(4, BiConsumer.class)) @@ -177,11 +177,21 @@ public final class BlockGenerator { .intercept(MethodDelegation.to(GetDirectSignalInterceptor.INSTANCE)) // isSignalSource .method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$isSignalSource)) - .intercept(MethodDelegation.to(IsSignalSourceInterceptor.INSTANCE)); + .intercept(MethodDelegation.to(IsSignalSourceInterceptor.INSTANCE)) + // playerWillDestroy + .method(ElementMatchers.is(CoreReflections.method$Block$playerWillDestroy)) + .intercept(MethodDelegation.to(PlayerWillDestroyInterceptor.INSTANCE)) + // spawnAfterBreak + .method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$spawnAfterBreak)) + .intercept(MethodDelegation.to(SpawnAfterBreakInterceptor.INSTANCE)); if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) { builder.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval)) .intercept(MethodDelegation.to(AffectNeighborsAfterRemovalInterceptor.INSTANCE)); } + if (CoreReflections.method$BlockBehaviour$onRemove != null) { + builder.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$onRemove)) + .intercept(MethodDelegation.to(OnRemoveInterceptor.INSTANCE)); + } Class clazz$CraftEngineBlock = builder.make().load(BlockGenerator.class.getClassLoader()).getLoaded(); constructor$CraftEngineBlock = MethodHandles.publicLookup().in(clazz$CraftEngineBlock) @@ -225,15 +235,9 @@ public final class BlockGenerator { public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); DelegatingBlock indicator = (DelegatingBlock) thisObj; - // todo chain updater - if (indicator.isNoteBlock()) { - if (CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) { - startNoteBlockChain(args); - } - } else if (indicator.isTripwire()) { - if (CoreReflections.clazz$ServerLevel.isInstance(args[posIndex])) { - - } + // todo better chain updater + if (indicator.isNoteBlock() && CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) { + startNoteBlockChain(args); } try { return holder.value().updateShape(thisObj, args, superMethod); @@ -501,6 +505,7 @@ public final class BlockGenerator { ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); try { holder.value().onExplosionHit(thisObj, args, superMethod); + superMethod.call(); } catch (Exception e) { CraftEngine.instance().logger().severe("Failed to run onExplosionHit", e); } @@ -611,6 +616,20 @@ public final class BlockGenerator { } } + public static class OnRemoveInterceptor { + public static final OnRemoveInterceptor INSTANCE = new OnRemoveInterceptor(); + + @RuntimeType + public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); + try { + holder.value().onRemove(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run onRemove", e); + } + } + } + public static class EntityInsideInterceptor { public static final EntityInsideInterceptor INSTANCE = new EntityInsideInterceptor(); @@ -624,4 +643,33 @@ public final class BlockGenerator { } } } + + public static class PlayerWillDestroyInterceptor { + public static final PlayerWillDestroyInterceptor INSTANCE = new PlayerWillDestroyInterceptor(); + + @RuntimeType + public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) throws Exception { + ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); + try { + return holder.value().playerWillDestroy(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run playerWillDestroy", e); + return superMethod.call(); + } + } + } + + public static class SpawnAfterBreakInterceptor { + public static final SpawnAfterBreakInterceptor INSTANCE = new SpawnAfterBreakInterceptor(); + + @RuntimeType + public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); + try { + holder.value().spawnAfterBreak(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run spawnAfterBreak", e); + } + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java index edd60946d..750a17039 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java @@ -100,6 +100,9 @@ public final class BlockStateGenerator { Object tool = FastNMS.INSTANCE.method$LootParams$Builder$getOptionalParameter(builder, MLootContextParams.TOOL); Item item = BukkitItemManager.instance().wrap(tool == null || FastNMS.INSTANCE.method$ItemStack$isEmpty(tool) ? null : FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(tool)); Object optionalPlayer = FastNMS.INSTANCE.method$LootParams$Builder$getOptionalParameter(builder, MLootContextParams.THIS_ENTITY); + if (!CoreReflections.clazz$Player.isInstance(optionalPlayer)) { + optionalPlayer = null; + } // do not drop if it's not the correct tool BlockSettings settings = state.settings(); @@ -115,7 +118,7 @@ public final class BlockStateGenerator { World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(serverLevel)); ContextHolder.Builder lootBuilder = new ContextHolder.Builder() .withParameter(DirectContextParameters.POSITION, new WorldPosition(world, FastNMS.INSTANCE.field$Vec3$x(vec3), FastNMS.INSTANCE.field$Vec3$y(vec3), FastNMS.INSTANCE.field$Vec3$z(vec3))); - if (item != null) { + if (!item.isEmpty()) { lootBuilder.withParameter(DirectContextParameters.ITEM_IN_HAND, item); } 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 c05455611..7a8016ace 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 @@ -20,11 +20,9 @@ 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; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -135,12 +133,7 @@ public class RecipeInjector { ); 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)); + SingleItemInput input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem)); CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); if (ceRecipe == null) { return Optional.empty(); @@ -186,12 +179,7 @@ public class RecipeInjector { } 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)); + SingleItemInput input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem)); CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); if (ceRecipe == null) { return Optional.empty(); @@ -232,12 +220,7 @@ public class RecipeInjector { 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)); + SingleItemInput input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem)); CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); if (ceRecipe == null) { return Optional.empty(); @@ -282,12 +265,7 @@ public class RecipeInjector { // 获取唯一内存地址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)); + SingleItemInput input = new SingleItemInput<>(new UniqueIdItem<>(wrappedItem.recipeIngredientId(), wrappedItem)); CustomCookingRecipe ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(injectedCacheCheck.customRecipeType(), input, injectedCacheCheck.lastCustomRecipe()); // 这个ce配方并不存在,那么应该返回空 if (ceRecipe == null) { 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 142205701..be7cc4e4f 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 @@ -1,6 +1,5 @@ package net.momirealms.craftengine.bukkit.plugin.network; -import com.google.gson.JsonObject; import io.netty.buffer.ByteBuf; import io.netty.channel.*; import io.netty.handler.codec.MessageToMessageDecoder; @@ -19,6 +18,7 @@ import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.CooldownData; +import net.momirealms.craftengine.core.plugin.logger.Debugger; import net.momirealms.craftengine.core.plugin.network.*; import net.momirealms.craftengine.core.util.*; import org.bukkit.Bukkit; @@ -43,8 +43,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static BukkitNetworkManager instance; private static final Map, TriConsumer> NMS_PACKET_HANDLERS = new HashMap<>(); // only for game stage for the moment - private static BiConsumer[] S2C_BYTE_BUFFER_PACKET_HANDLERS; - private static BiConsumer[] C2S_BYTE_BUFFER_PACKET_HANDLERS; + private static BiConsumer[] S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS; + private static BiConsumer[] C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS; private static void registerNMSPacketConsumer(final TriConsumer function, @Nullable Class packet) { if (packet == null) return; @@ -53,18 +53,18 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static void registerS2CByteBufPacketConsumer(final BiConsumer function, int id) { if (id == -1) return; - if (id < 0 || id >= S2C_BYTE_BUFFER_PACKET_HANDLERS.length) { + if (id < 0 || id >= S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS.length) { throw new IllegalArgumentException("Invalid packet id: " + id); } - S2C_BYTE_BUFFER_PACKET_HANDLERS[id] = function; + S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS[id] = function; } private static void registerC2SByteBufPacketConsumer(final BiConsumer function, int id) { if (id == -1) return; - if (id < 0 || id >= C2S_BYTE_BUFFER_PACKET_HANDLERS.length) { + if (id < 0 || id >= C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS.length) { throw new IllegalArgumentException("Invalid packet id: " + id); } - C2S_BYTE_BUFFER_PACKET_HANDLERS[id] = function; + C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS[id] = function; } private final BiConsumer packetConsumer; @@ -92,10 +92,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @SuppressWarnings("unchecked") public BukkitNetworkManager(BukkitCraftEngine plugin) { instance = this; - S2C_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxS2CPacketId()]; - C2S_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.maxC2SPacketId()]; - Arrays.fill(S2C_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING); - Arrays.fill(C2S_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING); + S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.s2cGamePackets()]; + C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.c2sGamePackets()]; + Arrays.fill(S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING); + Arrays.fill(C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING); hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; hasViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; this.plugin = plugin; @@ -117,8 +117,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes // set up mod channel this.plugin.javaPlugin().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.javaPlugin(), MOD_CHANNEL, this); this.plugin.javaPlugin().getServer().getMessenger().registerOutgoingPluginChannel(this.plugin.javaPlugin(), MOD_CHANNEL); - // 配置via频道 - this.plugin.javaPlugin().getServer().getMessenger().registerIncomingPluginChannel(this.plugin.javaPlugin(), VIA_CHANNEL, this); // Inject server channel try { Object server = CoreReflections.method$MinecraftServer$getServer.invoke(null); @@ -152,15 +150,15 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, NetworkReflections.clazz$ServerboundSignUpdatePacket); registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, NetworkReflections.clazz$ServerboundEditBookPacket); registerNMSPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD, NetworkReflections.clazz$ServerboundCustomPayloadPacket); - registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_PUSH, NetworkReflections.clazz$ClientboundResourcePackPushPacket); - registerNMSPacketConsumer(PacketConsumers.HANDSHAKE_C2S, NetworkReflections.clazz$ClientIntentionPacket); - registerNMSPacketConsumer(PacketConsumers.LOGIN_ACKNOWLEDGED, NetworkReflections.clazz$ServerboundLoginAcknowledgedPacket); 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); registerNMSPacketConsumer(PacketConsumers.ROTATE_HEAD, NetworkReflections.clazz$ClientboundRotateHeadPacket); registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_MOTION, NetworkReflections.clazz$ClientboundSetEntityMotionPacket); + registerNMSPacketConsumer(PacketConsumers.FINISH_CONFIGURATION, NetworkReflections.clazz$ClientboundFinishConfigurationPacket); + registerNMSPacketConsumer(PacketConsumers.LOGIN_FINISHED, NetworkReflections.clazz$ClientboundLoginFinishedPacket); + registerNMSPacketConsumer(PacketConsumers.UPDATE_TAGS, NetworkReflections.clazz$ClientboundUpdateTagsPacket); registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); @@ -176,6 +174,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TEAM_1_20_3 : PacketConsumers.TEAM_1_20, this.packetIds.clientboundSetPlayerTeamPacket()); 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.ADD_RECIPE_BOOK, this.packetIds.clientboundRecipeBookAddPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.PLACE_GHOST_RECIPE, this.packetIds.clientboundPlaceGhostRecipePacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.UPDATE_RECIPES, this.packetIds.clientboundUpdateRecipesPacket()); + registerS2CByteBufPacketConsumer(PacketConsumers.UPDATE_ADVANCEMENTS, this.packetIds.clientboundUpdateAdvancementsPacket()); registerS2CByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket()); registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY, this.packetIds.clientboundAddEntityPacket()); registerS2CByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket()); @@ -204,7 +206,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes this.resetUserArray(); if (VersionHelper.isFolia()) { player.getScheduler().runAtFixedRate(plugin.javaPlugin(), (t) -> user.tick(), - () -> plugin.debug(() -> "Player " + player.getName() + "'s entity scheduler is retired"), 1, 1); + () -> {}, 1, 1); } } } @@ -242,14 +244,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @Override public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte @NotNull [] message) { - if (channel.equals(VIA_CHANNEL)) { - BukkitServerPlayer user = this.plugin.adapt(player); - if (user != null) { - JsonObject payload = GsonHelper.get().fromJson(new String(message), JsonObject.class); - int version = payload.get("version").getAsInt(); - user.setProtocolVersion(version); - } - } } @Override @@ -653,6 +647,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } private void onNMSPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + Debugger.PACKET.debug(() -> "[C->S]" + packet.getClass()); handleNMSPacket(user, event, packet); } @@ -663,6 +658,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes onNMSPacketSend(player, event, p); } } else { + Debugger.PACKET.debug(() -> "[S->C]" + packet.getClass()); handleNMSPacket(player, event, packet); } } @@ -674,13 +670,13 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes protected void handleS2CByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - Optional.ofNullable(S2C_BYTE_BUFFER_PACKET_HANDLERS[packetID]) + Optional.ofNullable(S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS[packetID]) .ifPresent(function -> function.accept(user, event)); } protected void handleC2SByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - Optional.ofNullable(C2S_BYTE_BUFFER_PACKET_HANDLERS[packetID]) + Optional.ofNullable(C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS[packetID]) .ifPresent(function -> function.accept(user, event)); } 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 9614734c4..e9bc5537b 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 @@ -1,6 +1,8 @@ package net.momirealms.craftengine.bukkit.plugin.network; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.mojang.authlib.GameProfile; import com.mojang.datafixers.util.Either; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -21,7 +23,6 @@ import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManag import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.pack.BukkitPackManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor; import net.momirealms.craftengine.bukkit.plugin.network.handler.*; @@ -34,6 +35,8 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityType import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.core.advancement.network.AdvancementHolder; +import net.momirealms.craftengine.core.advancement.network.AdvancementProgress; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.font.FontManager; @@ -42,6 +45,9 @@ 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.recipe.network.legacy.LegacyRecipeHolder; +import net.momirealms.craftengine.core.item.recipe.network.modern.RecipeBookEntry; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -50,6 +56,7 @@ 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.plugin.logger.Debugger; import net.momirealms.craftengine.core.plugin.network.*; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockHitResult; @@ -64,7 +71,6 @@ import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.*; import org.bukkit.block.Block; -import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; @@ -127,8 +133,8 @@ public class PacketConsumers { 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.ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); + ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); ADD_ENTITY_HANDLERS[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); ADD_ENTITY_HANDLERS[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(true); ADD_ENTITY_HANDLERS[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(true); @@ -1254,9 +1260,6 @@ public class PacketConsumers { player.setConnectionState(ConnectionState.PLAY); Object dimensionKey; if (!VersionHelper.isOrAbove1_20_2()) { - if (BukkitNetworkManager.hasViaVersion()) { - user.setProtocolVersion(CraftEngine.instance().compatibilityManager().getPlayerProtocolVersion(player.uuid())); - } dimensionKey = NetworkReflections.methodHandle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet); } else { Object commonInfo = NetworkReflections.methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); @@ -1281,7 +1284,7 @@ public class PacketConsumers { // When the hotbar is full, the latest creative mode inventory can only be accessed when the player opens the inventory screen. Currently, it is not worth further handling this issue. public static final TriConsumer SET_CREATIVE_SLOT = (user, event, packet) -> { try { - if (user.protocolVersion().isVersionNewerThan(ProtocolVersion.V1_21_4)) return; + if (VersionHelper.isOrAbove1_21_4()) return; if (!user.isOnline()) return; BukkitServerPlayer player = (BukkitServerPlayer) user; if (VersionHelper.isFolia()) { @@ -1307,7 +1310,7 @@ public class PacketConsumers { 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.methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet)); - if (ItemUtils.isEmpty(item)) return; + if (ItemStackUtils.isEmpty(item)) return; if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) { return; } @@ -1323,11 +1326,14 @@ public class PacketConsumers { Key itemId = state.settings().itemId(); // no item available if (itemId == null) return; - BlockData data = BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()); - // compare item - if (data == null || !data.getMaterial().equals(item.getType())) return; + Object vanillaBlock = FastNMS.INSTANCE.method$BlockState$getBlock(state.vanillaBlockState().handle()); + Object vanillaBlockItem = FastNMS.INSTANCE.method$Block$asItem(vanillaBlock); + if (vanillaBlockItem == null) return; + Key addItemId = KeyUtils.namespacedKey2Key(item.getType().getKey()); + Key blockItemId = KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ITEM, vanillaBlockItem)); + if (!addItemId.equals(blockItemId)) return; ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, player); - if (ItemUtils.isEmpty(itemStack)) { + if (ItemStackUtils.isEmpty(itemStack)) { CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); return; } @@ -1336,7 +1342,7 @@ public class PacketConsumers { int emptySlot = -1; for (int i = 0; i < 9 + 27; i++) { ItemStack invItem = inventory.getItem(i); - if (ItemUtils.isEmpty(invItem)) { + if (ItemStackUtils.isEmpty(invItem)) { if (emptySlot == -1 && i < 9) emptySlot = i; continue; } @@ -1359,7 +1365,7 @@ public class PacketConsumers { } } else { if (item.getAmount() == 1) { - if (ItemUtils.isEmpty(inventory.getItem(slot - 36))) { + if (ItemStackUtils.isEmpty(inventory.getItem(slot - 36))) { BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, itemStack)); return; } @@ -1929,24 +1935,21 @@ public class PacketConsumers { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) { - Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - if (optionalTextComponent.isPresent()) { - Object textComponent = optionalTextComponent.get(); - String json = ComponentUtils.minecraftToJson(textComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (!tokens.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)))); - isChanged = true; - break; - } - } + if (entityDataId != EntityDataUtils.CUSTOM_NAME_DATA_ID) continue; + Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (optionalTextComponent.isEmpty()) continue; + Object textComponent = optionalTextComponent.get(); + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) continue; + Component component = AdventureHelper.jsonToComponent(json); + for (Map.Entry token : tokens.entrySet()) { + component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)))); + isChanged = true; + break; } if (isChanged) { event.setChanged(true); @@ -2093,7 +2096,13 @@ public class PacketConsumers { int stateId = buf.readVarInt(); int slot = buf.readShort(); Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + ItemStack itemStack; + try { + itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + } catch (Exception e) { + // 其他插件干的,比如某ty*****er,不要赖到ce头上 + return; + } BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { event.setChanged(true); buf.clear(); @@ -2117,11 +2126,11 @@ public class PacketConsumers { ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); if (VersionHelper.isOrAbove1_21_5()) { Item wrapped = BukkitItemManager.instance().wrap(itemStack); - if (wrapped != null && wrapped.isCustomItem()) { + if (!wrapped.isEmpty() && wrapped.isCustomItem()) { Object containerMenu = FastNMS.INSTANCE.field$Player$containerMenu(serverPlayer.serverPlayer()); if (containerMenu != null) { ItemStack carried = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.method$AbstractContainerMenu$getCarried(containerMenu)); - if (ItemUtils.isEmpty(carried)) { + if (ItemStackUtils.isEmpty(carried)) { event.setChanged(true); buf.clear(); buf.writeVarInt(event.packetID()); @@ -2280,73 +2289,55 @@ public class PacketConsumers { } }; - public static final TriConsumer RESOURCE_PACK_PUSH = (user, event, packet) -> { - try { - if (!VersionHelper.isOrAbove1_20_2()) return; - // we should only handle fake urls - String url = FastNMS.INSTANCE.field$ClientboundResourcePackPushPacket$url(packet); - if (!url.equals(BukkitPackManager.FAKE_URL)) { - return; - } - - event.setCancelled(true); - UUID packUUID = FastNMS.INSTANCE.field$ClientboundResourcePackPushPacket$uuid(packet); - ResourcePackHost host = CraftEngine.instance().packManager().resourcePackHost(); - host.requestResourcePackDownloadLink(user.uuid()).thenAccept(dataList -> { - if (dataList.isEmpty()) { - user.simulatePacket(FastNMS.INSTANCE.constructor$ServerboundResourcePackPacket$SUCCESSFULLY_LOADED(packUUID)); - return; - } - for (ResourcePackDownloadData data : dataList) { - Object newPacket = ResourcePackUtils.createPacket(data.uuid(), data.url(), data.sha1()); - user.sendPacket(newPacket, true); - user.addResourcePackUUID(data.uuid()); - } - }).exceptionally(throwable -> { - CraftEngine.instance().logger().warn("Failed to handle ClientboundResourcePackPushPacket", throwable); - user.simulatePacket(FastNMS.INSTANCE.constructor$ServerboundResourcePackPacket$SUCCESSFULLY_LOADED(packUUID)); - return null; - }); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundResourcePackPushPacket", e); - } - }; - - public static final TriConsumer HANDSHAKE_C2S = (user, event, packet) -> { - try { - if (BukkitNetworkManager.hasViaVersion()) return; - int protocolVersion = (int) NetworkReflections.methodHandle$ClientIntentionPacket$protocolVersionGetter.invokeExact(packet); - user.setProtocolVersion(protocolVersion); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientIntentionPacket", e); - } - }; - - public static final TriConsumer LOGIN_ACKNOWLEDGED = (user, event, packet) -> { - try { - if (BukkitNetworkManager.hasViaVersion()) { - user.setProtocolVersion(CraftEngine.instance().compatibilityManager().getPlayerProtocolVersion(user.uuid())); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundLoginAcknowledgedPacket", e); - } - }; - public static final TriConsumer RESOURCE_PACK_RESPONSE = (user, event, packet) -> { try { - if (user.sentResourcePack() || !Config.sendPackOnJoin() || !Config.kickOnDeclined()) return; - 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) { - Object kickPacket = NetworkReflections.constructor$ClientboundDisconnectPacket.newInstance( - ComponentUtils.adventureToMinecraft(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"))); - user.sendPacket(kickPacket, true); - user.nettyChannel().disconnect(); + Object action = FastNMS.INSTANCE.field$ServerboundResourcePackPacket$action(packet); + + if (VersionHelper.isOrAbove1_20_3()) { + UUID uuid = FastNMS.INSTANCE.field$ServerboundResourcePackPacket$id(packet); + if (!user.isResourcePackLoading(uuid)) { + // 不是CraftEngine发送的资源包,不管 + return; + } + } + + if (action == null) { + user.kick(Component.text("Corrupted ResourcePackResponse Packet")); return; } - if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$SUCCESSFULLY_LOADED) { - user.setSentResourcePack(true); + + // 检查是否是拒绝 + if (Config.kickOnDeclined()) { + if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DECLINED || action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DISCARDED) { + user.kick(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); + return; + } + } + + // 检查是否失败 + if (Config.kickOnFailedApply()) { + if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD + || (VersionHelper.isOrAbove1_20_3() && action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$INVALID_URL)) { + user.kick(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); + return; + } + } + + boolean isTerminal = action != NetworkReflections.instance$ServerboundResourcePackPacket$Action$ACCEPTED && action != NetworkReflections.instance$ServerboundResourcePackPacket$Action$DOWNLOADED; + if (isTerminal && VersionHelper.isOrAbove1_20_2()) { + event.setCancelled(true); + Object packetListener = FastNMS.INSTANCE.method$Connection$getPacketListener(user.connection()); + if (!CoreReflections.clazz$ServerConfigurationPacketListenerImpl.isInstance(packetListener)) return; + // 主线程上处理这个包 + CraftEngine.instance().scheduler().executeSync(() -> { + try { + // 当客户端发出多次成功包的时候,finish会报错,我们忽略他 + NetworkReflections.methodHandle$ServerCommonPacketListener$handleResourcePackResponse.invokeExact(packetListener, packet); + CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask.invokeExact(packetListener, CoreReflections.instance$ServerResourcePackConfigurationTask$TYPE); + } catch (Throwable e) { + Debugger.RESOURCE_PACK.warn(() -> "Cannot finish current task", e); + } + }); } } catch (Throwable e) { CraftEngine.instance().logger().warn("Failed to handle ServerboundResourcePackPacket", e); @@ -2417,4 +2408,176 @@ public class PacketConsumers { CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityMotionPacket", e); } }; + + // 这个包是由 JoinWorldTask 发出的,客户端收到后会返回 ServerboundFinishConfigurationPacket + @SuppressWarnings("unchecked") + public static final TriConsumer FINISH_CONFIGURATION = (user, event, packet) -> { + try { + if (!VersionHelper.isOrAbove1_20_2() || !Config.sendPackOnJoin()) { + // 防止后期调试进配置阶段造成问题 + user.setShouldProcessFinishConfiguration(false); + return; + } + + if (!user.shouldProcessFinishConfiguration()) return; + Object packetListener = FastNMS.INSTANCE.method$Connection$getPacketListener(user.connection()); + if (!CoreReflections.clazz$ServerConfigurationPacketListenerImpl.isInstance(packetListener)) { + return; + } + + // 防止后续加入的JoinWorldTask再次处理 + user.setShouldProcessFinishConfiguration(false); + + // 取消 ClientboundFinishConfigurationPacket,让客户端发呆,并结束掉当前的进入世界任务 + event.setCancelled(true); + try { + CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask.invokeExact(packetListener, CoreReflections.instance$JoinWorldTask$TYPE); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to finish current task for " + user.name(), e); + } + + if (VersionHelper.isOrAbove1_20_5()) { + // 1.20.5+开始会检查是否结束需要重新设置回去,不然不会发keepAlive包 + CoreReflections.methodHandle$ServerCommonPacketListenerImpl$closedSetter.invokeExact(packetListener, false); + } + + // 请求资源包 + ResourcePackHost host = CraftEngine.instance().packManager().resourcePackHost(); + host.requestResourcePackDownloadLink(user.uuid()).whenComplete((dataList, t) -> { + if (t != null) { + CraftEngine.instance().logger().warn("Failed to get pack data for player " + user.name(), t); + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + return; + } + if (dataList.isEmpty()) { + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + return; + } + Queue configurationTasks; + try { + configurationTasks = (Queue) CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter.invokeExact(packetListener); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to get configuration tasks for player " + user.name(), e); + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + return; + } + // 向配置阶段连接的任务重加入资源包的任务 + for (ResourcePackDownloadData data : dataList) { + configurationTasks.add(FastNMS.INSTANCE.constructor$ServerResourcePackConfigurationTask(ResourcePackUtils.createServerResourcePackInfo(data.uuid(), data.url(), data.sha1()))); + user.addResourcePackUUID(data.uuid()); + } + // 最后再加入一个 JoinWorldTask 并开始资源包任务 + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + }); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundFinishConfigurationPacket", e); + } + }; + + public static final TriConsumer LOGIN_FINISHED = (user, event, packet) -> { + try { + GameProfile gameProfile = FastNMS.INSTANCE.field$ClientboundLoginFinishedPacket$gameProfile(packet); + user.setName(gameProfile.getName()); + user.setUUID(gameProfile.getId()); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginFinishedPacket", e); + } + }; + + public static final BiConsumer ADD_RECIPE_BOOK = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + List entries = buf.readCollection(ArrayList::new, byteBuf -> { + RecipeBookEntry entry = RecipeBookEntry.read(byteBuf); + entry.applyClientboundData((BukkitServerPlayer) user); + return entry; + }); + boolean replace = buf.readBoolean(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeCollection(entries, ((byteBuf, recipeBookEntry) -> recipeBookEntry.write(byteBuf))); + buf.writeBoolean(replace); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundRecipeBookAddPacket", e); + } + }; + + public static final BiConsumer PLACE_GHOST_RECIPE = (user, event) -> { + try { + if (!VersionHelper.isOrAbove1_21_2()) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readContainerId(); + RecipeDisplay display = RecipeDisplay.read(buf); + display.applyClientboundData((BukkitServerPlayer) user); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + display.write(buf); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundPlaceGhostRecipePacket", e); + } + }; + + public static final BiConsumer UPDATE_RECIPES = (user, event) -> { + try { + if (VersionHelper.isOrAbove1_21_2()) return; + FriendlyByteBuf buf = event.getBuffer(); + List holders = buf.readCollection(ArrayList::new, byteBuf -> { + LegacyRecipeHolder holder = LegacyRecipeHolder.read(byteBuf); + holder.recipe().applyClientboundData((BukkitServerPlayer) user); + return holder; + }); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeCollection(holders, ((byteBuf, recipeHolder) -> recipeHolder.write(byteBuf))); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateRecipesPacket", e); + } + }; + + public static final BiConsumer UPDATE_ADVANCEMENTS = (user, event) -> { + try { + FriendlyByteBuf buf = event.getBuffer(); + boolean reset = buf.readBoolean(); + List added = buf.readCollection(ArrayList::new, byteBuf -> { + AdvancementHolder holder = AdvancementHolder.read(byteBuf); + holder.applyClientboundData((BukkitServerPlayer) user); + return holder; + }); + Set removed = buf.readCollection(Sets::newLinkedHashSetWithExpectedSize, FriendlyByteBuf::readKey); + Map progress = buf.readMap(FriendlyByteBuf::readKey, AdvancementProgress::read); + + boolean showAdvancement = false; + if (VersionHelper.isOrAbove1_21_5()) { + showAdvancement = buf.readBoolean(); + } + + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + + buf.writeBoolean(reset); + buf.writeCollection(added, (byteBuf, advancementHolder) -> advancementHolder.write(byteBuf)); + buf.writeCollection(removed, FriendlyByteBuf::writeKey); + buf.writeMap(progress, FriendlyByteBuf::writeKey, (byteBuf, advancementProgress) -> advancementProgress.write(byteBuf)); + if (VersionHelper.isOrAbove1_21_5()) { + buf.writeBoolean(showAdvancement); + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateAdvancementsPacket", e); + } + }; + + public static final TriConsumer UPDATE_TAGS = (user, event, packet) -> { + try { + Object modifiedPacket = BukkitBlockManager.instance().cachedUpdateTagsPacket(); + if (packet.equals(modifiedPacket) || modifiedPacket == null) return; + event.replacePacket(modifiedPacket); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateTagsPacket", 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 678e06f1a..bef170327 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 @@ -54,9 +54,17 @@ public interface PacketIds { int clientboundBlockEventPacket(); + int clientboundRecipeBookAddPacket(); + + int clientboundPlaceGhostRecipePacket(); + + int clientboundUpdateAdvancementsPacket(); + int serverboundContainerClickPacket(); int serverboundSetCreativeModeSlotPacket(); int serverboundInteractPacket(); + + int clientboundUpdateRecipesPacket(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java index c726a7a54..c36ef9352 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ArmorStandPacketHandler.java @@ -32,25 +32,22 @@ public class ArmorStandPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) { - @SuppressWarnings("unchecked") - Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - if (optionalTextComponent.isPresent()) { - Object textComponent = optionalTextComponent.get(); - String json = ComponentUtils.minecraftToJson(textComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (!tokens.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)))); - isChanged = true; - break; - } - } + if (entityDataId != EntityDataUtils.CUSTOM_NAME_DATA_ID) continue; + @SuppressWarnings("unchecked") + Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (optionalTextComponent.isEmpty()) continue; + Object textComponent = optionalTextComponent.get(); + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) continue; + Component component = AdventureHelper.jsonToComponent(json); + for (Map.Entry token : tokens.entrySet()) { + component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)))); + isChanged = true; + break; } if (isChanged) { event.setChanged(true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java index 8ed3f8f7b..207cd4842 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java @@ -47,22 +47,20 @@ public class BlockDisplayPacketHandler implements EntityPacketHandler { } else if (Config.interceptEntityName() && entityDataId == EntityDataUtils.CUSTOM_NAME_DATA_ID) { @SuppressWarnings("unchecked") Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - if (optionalTextComponent.isPresent()) { - Object textComponent = optionalTextComponent.get(); - String json = ComponentUtils.minecraftToJson(textComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (!tokens.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( - entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)) - )); - isChanged = true; - } + if (optionalTextComponent.isEmpty()) continue; + Object textComponent = optionalTextComponent.get(); + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) continue; + Component component = AdventureHelper.jsonToComponent(json); + for (Map.Entry token : tokens.entrySet()) { + component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)) + )); + isChanged = true; } } if (isChanged) { 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 df172d479..7e60b7671 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 @@ -17,6 +17,7 @@ import java.util.Optional; public class CommonItemPacketHandler implements EntityPacketHandler { public static final CommonItemPacketHandler INSTANCE = new CommonItemPacketHandler(); + private static long lastWarningTime = 0; @Override public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { @@ -27,25 +28,28 @@ public class CommonItemPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); 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()) { - isChanged = true; - itemStack = optional.get(); - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( - entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack) - )); - break; + if (entityDataId != EntityDataUtils.ITEM_DATA_ID) continue; + Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) { + long time = System.currentTimeMillis(); + if (time - lastWarningTime > 5000) { + BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; + CraftEngine.instance().logger().severe("An issue was detected while applying item-related entity data for '" + serverPlayer.name() + + "'. Please execute the command '/ce debug entity-id " + serverPlayer.world().name() + " " + id + "' and provide a screenshot for further investigation."); + lastWarningTime = time; } + continue; } + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); + Optional optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user); + if (optional.isEmpty()) continue; + isChanged = true; + itemStack = optional.get(); + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack) + )); + break; } if (isChanged) { event.setChanged(true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java index 0cd4d4417..911e661e3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemDisplayPacketHandler.java @@ -25,20 +25,18 @@ public class ItemDisplayPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId == EntityDataUtils.DISPLAYED_ITEM_DATA_ID) { - Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); - Optional optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user); - if (optional.isPresent()) { - isChanged = true; - itemStack = optional.get(); - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( - entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack) - )); - break; - } - } + if (entityDataId != EntityDataUtils.DISPLAYED_ITEM_DATA_ID) continue; + Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); + Optional optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user); + if (optional.isEmpty()) continue; + isChanged = true; + itemStack = optional.get(); + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack) + )); + break; } if (isChanged) { event.setChanged(true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java new file mode 100644 index 000000000..1c75b767f --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ItemFramePacketHandler.java @@ -0,0 +1,62 @@ +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; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.bukkit.inventory.ItemStack; + +import java.util.List; +import java.util.Optional; + +public class ItemFramePacketHandler implements EntityPacketHandler { + public static final ItemFramePacketHandler INSTANCE = new ItemFramePacketHandler(); + private static long lastWarningTime = 0; + + @Override + public void handleSetEntityData(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + boolean isChanged = false; + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId != EntityDataUtils.ITEM_FRAME_DATA_ID) continue; + Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (!CoreReflections.clazz$ItemStack.isInstance(nmsItemStack)) { + long time = System.currentTimeMillis(); + if (time - lastWarningTime > 5000) { + BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; + CraftEngine.instance().logger().severe("An issue was detected while applying item-related entity data for '" + serverPlayer.name() + + "'. Please execute the command '/ce debug entity-id " + serverPlayer.world().name() + " " + id + "' and provide a screenshot for further investigation."); + lastWarningTime = time; + } + continue; + } + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); + Optional optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user); + if (optional.isEmpty()) continue; + isChanged = true; + itemStack = optional.get(); + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( + entityDataId, serializer, FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack) + )); + break; + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java index 2d81c30b9..a9cea9178 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/TextDisplayPacketHandler.java @@ -31,22 +31,20 @@ public class TextDisplayPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId == EntityDataUtils.TEXT_DATA_ID) { - Object textComponent = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - if (textComponent == CoreReflections.instance$Component$empty) break; - String json = ComponentUtils.minecraftToJson(textComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (!tokens.isEmpty()) { - Component component = AdventureHelper.jsonToComponent(json); - for (Map.Entry token : tokens.entrySet()) { - component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); - } - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, ComponentUtils.adventureToMinecraft(component))); - isChanged = true; - break; - } + if (entityDataId != EntityDataUtils.TEXT_DATA_ID) continue; + Object textComponent = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (textComponent == CoreReflections.instance$Component$empty) break; + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) continue; + Component component = AdventureHelper.jsonToComponent(json); + for (Map.Entry token : tokens.entrySet()) { + component = component.replaceText(b -> b.matchLiteral(token.getKey()).replacement(token.getValue())); } + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, ComponentUtils.adventureToMinecraft(component))); + isChanged = true; + break; } if (isChanged) { event.setChanged(true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java index 3bbe1f197..e8d383aec 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java @@ -21,8 +21,8 @@ public class PacketIdFinder { if (VersionHelper.isOrAbove1_21()) { Object packetReport = CoreReflections.constructor$PacketReport.newInstance((Object) null); JsonElement jsonElement = (JsonElement) CoreReflections.method$PacketReport$serializePackets.invoke(packetReport); - var play = jsonElement.getAsJsonObject().get("play"); - for (var entry : play.getAsJsonObject().entrySet()) { + JsonElement play = jsonElement.getAsJsonObject().get("play"); + for (Map.Entry entry : play.getAsJsonObject().entrySet()) { Map ids = new HashMap<>(); gamePacketIdsByName.put(entry.getKey(), ids); for (var entry2 : entry.getValue().getAsJsonObject().entrySet()) { @@ -40,6 +40,7 @@ public class PacketIdFinder { maxS2CPacketId = calculateMaxId("clientbound"); maxC2SPacketId = calculateMaxId("serverbound"); } + private static int calculateMaxId(String direction) { if (VersionHelper.isOrAbove1_20_5()) { return gamePacketIdsByName.getOrDefault(direction, Collections.emptyMap()).size(); @@ -48,11 +49,11 @@ public class PacketIdFinder { } } - public static int maxC2SPacketId() { + public static int c2sGamePackets() { return maxC2SPacketId; } - public static int maxS2CPacketId() { + public static int s2cGamePackets() { return maxS2CPacketId; } 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 d9ff6e609..34981a06b 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 @@ -149,4 +149,24 @@ public class PacketIds1_20 implements PacketIds { public int serverboundInteractPacket() { return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundInteractPacket); } + + @Override + public int clientboundRecipeBookAddPacket() { + return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundRecipeBookAddPacket); + } + + @Override + public int clientboundPlaceGhostRecipePacket() { + return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundPlaceGhostRecipePacket); + } + + @Override + public int clientboundUpdateRecipesPacket() { + return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundUpdateRecipesPacket); + } + + @Override + public int clientboundUpdateAdvancementsPacket() { + return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundUpdateAdvancementsPacket); + } } 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 03d66538a..216b11d56 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 @@ -134,6 +134,26 @@ public class PacketIds1_20_5 implements PacketIds { return PacketIdFinder.clientboundByName("minecraft:block_event"); } + @Override + public int clientboundRecipeBookAddPacket() { + return PacketIdFinder.clientboundByName("minecraft:recipe_book_add"); + } + + @Override + public int clientboundPlaceGhostRecipePacket() { + return PacketIdFinder.clientboundByName("minecraft:place_ghost_recipe"); + } + + @Override + public int clientboundUpdateRecipesPacket() { + return PacketIdFinder.clientboundByName("minecraft:update_recipes"); + } + + @Override + public int clientboundUpdateAdvancementsPacket() { + return PacketIdFinder.clientboundByName("minecraft:update_advancements"); + } + @Override public int serverboundContainerClickPacket() { return PacketIdFinder.serverboundByName("minecraft:container_click"); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java index 8ce9fe566..fa15e41c7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/bukkit/CraftBukkitReflections.java @@ -262,7 +262,7 @@ public final class CraftBukkitReflections { ); public static final Field field$CraftBlockEntityState$tileEntity = requireNonNull( - ReflectionUtils.getDeclaredField(clazz$CraftBlockEntityState, 0) + ReflectionUtils.getInstanceDeclaredField(clazz$CraftBlockEntityState, 0) ); public static final Method method$CraftInventory$getInventory = requireNonNull( 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 ee3439b35..0bd7981a8 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 @@ -9,6 +9,7 @@ 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.MiscUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -289,11 +290,11 @@ public final class CoreReflections { )).getInterfaces()[0] ); - public static final Method method$RegistryAccess$registryOrThrow = requireNonNull( - ReflectionUtils.getMethod( - clazz$RegistryAccess, clazz$Registry, clazz$ResourceKey - ) - ); +// public static final Method method$RegistryAccess$registryOrThrow = requireNonNull( +// ReflectionUtils.getMethod( +// clazz$RegistryAccess, clazz$Registry, clazz$ResourceKey +// ) +// ); public static final Method method$Registry$register = requireNonNull( ReflectionUtils.getStaticMethod( @@ -328,58 +329,52 @@ public final class CoreReflections { ) ); - public static final Method method$Registry$getKey = requireNonNull( - ReflectionUtils.getMethod(clazz$Registry, clazz$ResourceLocation, Object.class) - ); +// public static final Method method$Registry$getKey = requireNonNull( +// ReflectionUtils.getMethod(clazz$Registry, clazz$ResourceLocation, Object.class) +// ); - public static final Method method$Registry$get = requireNonNull( - ReflectionUtils.getMethods( - clazz$Registry, Object.class, clazz$ResourceLocation - ).stream().filter(m -> m.getReturnType() != Optional.class).findAny().orElse(null) - ); - - // use ResourceLocation - public static final Method method$Registry$getHolder0; - // use ResourceKey - public static final Method method$Registry$getHolder1; - - static { - List methods = ReflectionUtils.getMethods(clazz$Registry, Optional.class, clazz$ResourceLocation); - Method theMethod1 = null; - for (Method method : methods) { - Type returnType = method.getGenericReturnType(); - if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == clazz$ResourceLocation) { - if (returnType instanceof ParameterizedType parameterizedType) { - Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); - if (actualTypeArguments.length == 1) { - if (actualTypeArguments[0] instanceof ParameterizedType) { - theMethod1 = method; - } - } - } - } - } - method$Registry$getHolder0 = theMethod1; - } - - static { - List methods = ReflectionUtils.getMethods(clazz$Registry, Optional.class, clazz$ResourceKey); - Method theMethod1 = null; - for (Method method : methods) { - Type returnType = method.getGenericReturnType(); - if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == clazz$ResourceKey) { - if (returnType instanceof ParameterizedType parameterizedType) { - Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); - if (actualTypeArguments.length == 1) { - if (actualTypeArguments[0] instanceof ParameterizedType) { - theMethod1 = method; - } - } - } - } - } - method$Registry$getHolder1 = theMethod1; - } +// // use ResourceLocation +// public static final Method method$Registry$getHolder0; +// // use ResourceKey +// public static final Method method$Registry$getHolder1; +// +// static { +// List methods = ReflectionUtils.getMethods(clazz$Registry, Optional.class, clazz$ResourceLocation); +// Method theMethod1 = null; +// for (Method method : methods) { +// Type returnType = method.getGenericReturnType(); +// if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == clazz$ResourceLocation) { +// if (returnType instanceof ParameterizedType parameterizedType) { +// Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); +// if (actualTypeArguments.length == 1) { +// if (actualTypeArguments[0] instanceof ParameterizedType) { +// theMethod1 = method; +// } +// } +// } +// } +// } +// method$Registry$getHolder0 = theMethod1; +// } +// +// static { +// List methods = ReflectionUtils.getMethods(clazz$Registry, Optional.class, clazz$ResourceKey); +// Method theMethod1 = null; +// for (Method method : methods) { +// Type returnType = method.getGenericReturnType(); +// if (method.getParameterCount() == 1 && method.getParameterTypes()[0] == clazz$ResourceKey) { +// if (returnType instanceof ParameterizedType parameterizedType) { +// Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); +// if (actualTypeArguments.length == 1) { +// if (actualTypeArguments[0] instanceof ParameterizedType) { +// theMethod1 = method; +// } +// } +// } +// } +// } +// method$Registry$getHolder1 = theMethod1; +// } public static final Class clazz$BlockPos = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( @@ -1328,6 +1323,10 @@ public final class CoreReflections { public static final Field field$BlockStateBase$lightBlock = ReflectionUtils.getInstanceDeclaredField(clazz$BlockStateBase, int.class, 1); + // 1.20-1.21.1 + public static final Field field$BlockStateBase$opacityIfCached = + ReflectionUtils.getInstanceDeclaredField(clazz$BlockStateBase, int.class, 1); + public static final Class clazz$AABB = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( "world.phys.AxisAlignedBB", @@ -1825,18 +1824,10 @@ public final class CoreReflections { ReflectionUtils.getInstanceDeclaredField(clazz$Abilities, boolean.class, 2) ); - public static final Field field$Abilities$instabuild = requireNonNull( - ReflectionUtils.getInstanceDeclaredField(clazz$Abilities, boolean.class, 3) - ); - public static final Field field$Abilities$mayBuild = requireNonNull( ReflectionUtils.getInstanceDeclaredField(clazz$Abilities, boolean.class, 4) ); - public static final Field field$Player$abilities = requireNonNull( - ReflectionUtils.getInstanceDeclaredField(clazz$Player, clazz$Abilities, 0) - ); - public static final Class clazz$FlowingFluid = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( "world.level.material.FluidTypeFlowing", @@ -2299,12 +2290,26 @@ public final class CoreReflections { public static final Constructor constructor$SmithingTransformRecipe = requireNonNull( VersionHelper.isOrAbove1_21_5() - ? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, clazz$Ingredient, Optional.class, clazz$TransmuteResult) - : VersionHelper.isOrAbove1_21_2() - ? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, Optional.class, Optional.class, clazz$ItemStack) - : VersionHelper.isOrAbove1_20_2() - ? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack) - : ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack) + ? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, clazz$Ingredient, Optional.class, clazz$TransmuteResult) + : VersionHelper.isOrAbove1_21_2() + ? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, Optional.class, Optional.class, clazz$ItemStack) + : VersionHelper.isOrAbove1_20_2() + ? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack) + : ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack) + ); + + public static final Class clazz$SmithingTrimRecipe = requireNonNull( + ReflectionUtils.getClazz(BukkitReflectionUtils.assembleMCClass("world.item.crafting.SmithingTrimRecipe")) + ); + + public static final Constructor constructor$SmithingTrimRecipe = requireNonNull( + VersionHelper.isOrAbove1_21_5() ? + ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$Holder) : + VersionHelper.isOrAbove1_21_2() ? + ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, Optional.class, Optional.class, Optional.class) : + VersionHelper.isOrAbove1_20_2() ? + ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient) : + ReflectionUtils.getConstructor(clazz$SmithingTrimRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient) ); public static final Method method$RecipeManager$addRecipe = requireNonNull( @@ -3588,4 +3593,241 @@ public final class CoreReflections { "nbt.CompoundTag" ) ); + + public static final Class clazz$TrimPattern = requireNonNull( + VersionHelper.isOrAbove1_21_2() ? + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.equipment.trim.TrimPattern", + "world.item.equipment.trim.TrimPattern" + ) : + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.armortrim.TrimPattern", + "world.item.armortrim.TrimPattern" + ) + ); + + public static final Class clazz$TrimMaterial = requireNonNull( + VersionHelper.isOrAbove1_21_2() ? + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.equipment.trim.TrimMaterial", + "world.item.equipment.trim.TrimMaterial" + ) : + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.armortrim.TrimMaterial", + "world.item.armortrim.TrimMaterial" + ) + ); + + public static final Class clazz$MaterialAssetGroup = BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.equipment.trim.MaterialAssetGroup", + "world.item.equipment.trim.MaterialAssetGroup" + ); + + public static final Method method$MaterialAssetGroup$create = Optional.ofNullable(clazz$MaterialAssetGroup) + .map(it -> ReflectionUtils.getStaticMethod(it, it, String.class)).orElse(null); + + public static final Constructor constructor$TrimPattern = requireNonNull( + VersionHelper.isOrAbove1_21_5() ? + ReflectionUtils.getConstructor(clazz$TrimPattern, clazz$ResourceLocation, clazz$Component, boolean.class) : + VersionHelper.isOrAbove1_20_2() ? + ReflectionUtils.getConstructor(clazz$TrimPattern, clazz$ResourceLocation, clazz$Holder, clazz$Component, boolean.class) : + ReflectionUtils.getConstructor(clazz$TrimPattern, clazz$ResourceLocation, clazz$Holder, clazz$Component) + ); + + public static final Constructor constructor$TrimMaterial = requireNonNull( + VersionHelper.isOrAbove1_21_5() ? + ReflectionUtils.getConstructor(clazz$TrimMaterial, clazz$MaterialAssetGroup, clazz$Component) : + VersionHelper.isOrAbove1_21_4() ? + ReflectionUtils.getConstructor(clazz$TrimMaterial, String.class, clazz$Holder, Map.class, clazz$Component) : + ReflectionUtils.getConstructor(clazz$TrimMaterial, String.class, clazz$Holder, float.class, Map.class, clazz$Component) + ); + + public static final Class clazz$ServerConfigurationPacketListenerImpl = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("server.network.ServerConfigurationPacketListenerImpl") + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Field field$ServerConfigurationPacketListenerImpl$configurationTasks = Optional.ofNullable(clazz$ServerConfigurationPacketListenerImpl) + .map(it -> ReflectionUtils.getDeclaredField(it, Queue.class, 0)) + .orElse(null); + + public static final MethodHandle methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter = + ReflectionUtils.unreflectGetter(field$ServerConfigurationPacketListenerImpl$configurationTasks) + .asType(MethodType.methodType(Queue.class, Object.class)); + } else { + methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter = null; + } + } catch (IllegalAccessException e) { + throw new ReflectionInitException("Failed to initialize reflection", e); + } + } + + public static final Class clazz$JoinWorldTask = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("server.network.config.JoinWorldTask") + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Constructor constructor$JoinWorldTask = Optional.ofNullable(clazz$JoinWorldTask) + .map(ReflectionUtils::getTheOnlyConstructor) + .orElse(null); + + public static final Class clazz$ConfigurationTask$Type = MiscUtils.requireNonNullIf( + BukkitReflectionUtils.findReobfOrMojmapClass( + "server.network.ConfigurationTask$a", + "server.network.ConfigurationTask$Type" + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Field field$JoinWorldTask$TYPE = Optional.ofNullable(clazz$JoinWorldTask) + .map(it -> ReflectionUtils.getDeclaredField(it, clazz$ConfigurationTask$Type, 0)) + .orElse(null); + + public static final Class clazz$ServerResourcePackConfigurationTask = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("server.network.config.ServerResourcePackConfigurationTask") + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Field field$ServerResourcePackConfigurationTask$TYPE = Optional.ofNullable(clazz$ServerResourcePackConfigurationTask) + .map(it -> ReflectionUtils.getDeclaredField(it, clazz$ConfigurationTask$Type, 0)) + .orElse(null); + + public static final Object instance$JoinWorldTask; + public static final Object instance$JoinWorldTask$TYPE; + public static final Object instance$ServerResourcePackConfigurationTask$TYPE; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + instance$JoinWorldTask = constructor$JoinWorldTask.newInstance(); + instance$JoinWorldTask$TYPE = field$JoinWorldTask$TYPE.get(null); + instance$ServerResourcePackConfigurationTask$TYPE = field$ServerResourcePackConfigurationTask$TYPE.get(null); + } else { + instance$JoinWorldTask = null; + instance$JoinWorldTask$TYPE = null; + instance$ServerResourcePackConfigurationTask$TYPE = null; + } + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize reflection", e); + } + } + + // 注释的这些说不定以后调试有用 + // public static final Class clazz$ConfigurationTask = MiscUtils.requireNonNullIf( + // ReflectionUtils.getClazz( + // BukkitReflectionUtils.assembleMCClass("server.network.ConfigurationTask") + // ), + // VersionHelper.isOrAbove1_20_2() + // ); + // + // public static final Field field$ServerConfigurationPacketListenerImpl$currentTask = MiscUtils.requireNonNullIf( + // ReflectionUtils.getDeclaredField(clazz$ServerConfigurationPacketListenerImpl, clazz$ConfigurationTask, 0), + // VersionHelper.isOrAbove1_20_2() + // ); + + // 1.20.2+ + public static final Method method$ServerConfigurationPacketListenerImpl$finishCurrentTask = Optional.ofNullable(clazz$ServerConfigurationPacketListenerImpl) + .map(it -> ReflectionUtils.getDeclaredMethod(it, void.class, clazz$ConfigurationTask$Type)) + .orElse( null); + + public static final Field field$ServerCommonPacketListenerImpl$closed = MiscUtils.requireNonNullIf( + ReflectionUtils.getDeclaredField(clazz$ServerCommonPacketListenerImpl, boolean.class, VersionHelper.isOrAbove1_21_6() ? 1 : 2), + VersionHelper.isOrAbove1_20_5() + ); + + public static final MethodHandle methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask; + public static final MethodHandle methodHandle$ServerCommonPacketListenerImpl$closedSetter; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = + ReflectionUtils.unreflectMethod(method$ServerConfigurationPacketListenerImpl$finishCurrentTask) + .asType(MethodType.methodType(void.class, Object.class, Object.class)); + methodHandle$ServerCommonPacketListenerImpl$closedSetter = + ReflectionUtils.unreflectSetter(field$ServerCommonPacketListenerImpl$closed) + .asType(MethodType.methodType(void.class, Object.class, boolean.class)); + } else { + methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask = null; + methodHandle$ServerCommonPacketListenerImpl$closedSetter = null; + } + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize reflection", e); + } + } + + public static final Method method$Block$playerWillDestroy = requireNonNull( + ReflectionUtils.getDeclaredMethod( + clazz$Block, + VersionHelper.isOrAbove1_20_3() ? clazz$BlockState : void.class, + clazz$Level, clazz$BlockPos, clazz$BlockState, clazz$Player + ) + ); + + public static final Class clazz$BlockItem = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.ItemBlock", + "world.item.BlockItem" + ) + ); + + public static final Class clazz$ArmorTrim = requireNonNull( + ReflectionUtils.getClazz( + VersionHelper.isOrAbove1_21_2() ? + BukkitReflectionUtils.assembleMCClass("world.item.equipment.trim.ArmorTrim") : + BukkitReflectionUtils.assembleMCClass("world.item.armortrim.ArmorTrim") + ) + ); + + public static final Field field$ArmorTrim$CODEC = requireNonNull( + ReflectionUtils.getDeclaredField(clazz$ArmorTrim, Codec.class, 0) + ); + + public static final Codec instance$ArmorTrim$CODEC; + + static { + try { + instance$ArmorTrim$CODEC = (Codec) field$ArmorTrim$CODEC.get(null); + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize ArmorTrim CODEC", e); + } + } + + public static final Method method$ArmorTrim$setTrim = ReflectionUtils.getStaticMethod( + clazz$ArmorTrim, boolean.class, clazz$RegistryAccess, clazz$ItemStack, clazz$ArmorTrim + ); + + public static final Method method$ArmorTrim$getTrim = + VersionHelper.isOrAbove1_20_2() ? + ReflectionUtils.getStaticMethod(clazz$ArmorTrim, Optional.class, clazz$RegistryAccess, clazz$ItemStack, boolean.class) : + ReflectionUtils.getStaticMethod(clazz$ArmorTrim, Optional.class, clazz$RegistryAccess, clazz$ItemStack); + + public static final Method method$BlockBehaviour$spawnAfterBreak = requireNonNull( + ReflectionUtils.getDeclaredMethod( + clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$ServerLevel, clazz$BlockPos, clazz$ItemStack, boolean.class + ) + ); + + // 1.20~1.21.4 + public static final Method method$BlockBehaviour$onRemove = MiscUtils.requireNonNullIf( + ReflectionUtils.getDeclaredMethod( + clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$BlockState, boolean.class + ), + !VersionHelper.isOrAbove1_21_5() + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MAttributeHolders.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MAttributeHolders.java index 2f3a93a6a..d64ac0a56 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MAttributeHolders.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MAttributeHolders.java @@ -3,8 +3,6 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.util.VersionHelper; -import java.util.Optional; - public final class MAttributeHolders { private MAttributeHolders() {} @@ -12,26 +10,20 @@ public final class MAttributeHolders { public static final Object BLOCK_INTERACTION_RANGE; public static final Object SCALE; - @SuppressWarnings("unchecked") - private static Object getById(String id) throws ReflectiveOperationException { + private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); - Optional optionalHolder = (Optional) CoreReflections.method$Registry$getHolder0.invoke(MBuiltInRegistries.ATTRIBUTE, rl); - return optionalHolder.orElse(null); + return FastNMS.INSTANCE.method$Registry$getHolderByResourceLocation(MBuiltInRegistries.ATTRIBUTE, rl).get(); } static { - try { - if (VersionHelper.isOrAbove1_20_5()) { - BLOCK_BREAK_SPEED = getById(VersionHelper.isOrAbove1_21_2() ? "block_break_speed" : "player.block_break_speed"); - BLOCK_INTERACTION_RANGE = getById(VersionHelper.isOrAbove1_21_2() ? "block_interaction_range" : "player.block_interaction_range"); - SCALE = getById(VersionHelper.isOrAbove1_21_2() ? "scale" : "generic.scale"); - } else { - BLOCK_BREAK_SPEED = null; - BLOCK_INTERACTION_RANGE = null; - SCALE = null; - } - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); + if (VersionHelper.isOrAbove1_20_5()) { + BLOCK_BREAK_SPEED = getById(VersionHelper.isOrAbove1_21_2() ? "block_break_speed" : "player.block_break_speed"); + BLOCK_INTERACTION_RANGE = getById(VersionHelper.isOrAbove1_21_2() ? "block_interaction_range" : "player.block_interaction_range"); + SCALE = getById(VersionHelper.isOrAbove1_21_2() ? "scale" : "generic.scale"); + } else { + BLOCK_BREAK_SPEED = null; + BLOCK_INTERACTION_RANGE = null; + SCALE = null; } } } 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 2c9355fdf..2cf9d1613 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 @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.core.util.VersionHelper; public final class MBlocks { @@ -19,26 +18,22 @@ public final class MBlocks { public static final Object SHULKER_BOX; public static final Object COMPOSTER; - private static Object getById(String id) throws ReflectiveOperationException { + private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); - return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, rl); + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, rl); } static { - try { - AIR = getById("air"); - AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR); - FIRE = getById("fire"); - SOUL_FIRE = getById("soul_fire"); - STONE = getById("stone"); - STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE); - ICE = getById("ice"); - SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass"); - SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS); - SHULKER_BOX = getById("shulker_box"); - COMPOSTER = getById("composter"); - } catch (ReflectiveOperationException e) { - throw new ReflectionInitException("Failed to init Blocks", e); - } + AIR = getById("air"); + AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR); + FIRE = getById("fire"); + SOUL_FIRE = getById("soul_fire"); + STONE = getById("stone"); + STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE); + ICE = getById("ice"); + SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass"); + SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS); + SHULKER_BOX = getById("shulker_box"); + COMPOSTER = getById("composter"); } } 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 ee4129d3d..ef5ab374d 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 @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.core.util.VersionHelper; public final class MEntityTypes { @@ -60,72 +59,68 @@ public final class MEntityTypes { public static final Object PLAYER; public static final int PLAYER$registryId; - private static Object getById(String id) throws ReflectiveOperationException { + private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); - return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.ENTITY_TYPE, rl); + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ENTITY_TYPE, rl); } - private static int getRegistryId(Object type) throws ReflectiveOperationException { + private static int getRegistryId(Object type) { if (type == null) return -1; - return (int) CoreReflections.method$Registry$getId.invoke(MBuiltInRegistries.ENTITY_TYPE, type); + return FastNMS.INSTANCE.method$Registry$getId(MBuiltInRegistries.ENTITY_TYPE, type); } static { - try { - 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); - HAPPY_GHAST = VersionHelper.isOrAbove1_21_6() ? getById("happy_ghast") : null; - HAPPY_GHAST$registryId = getRegistryId(HAPPY_GHAST); - PLAYER = getById("player"); - PLAYER$registryId = getRegistryId(PLAYER); - ARROW = getById("arrow"); - ARROW$registryId = getRegistryId(ARROW); - SPECTRAL_ARROW = getById("spectral_arrow"); - SPECTRAL_ARROW$registryId = getRegistryId(SPECTRAL_ARROW); - } catch (ReflectiveOperationException e) { - throw new ReflectionInitException("Failed to init EntityTypes", e); - } + 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); + HAPPY_GHAST = VersionHelper.isOrAbove1_21_6() ? getById("happy_ghast") : null; + HAPPY_GHAST$registryId = getRegistryId(HAPPY_GHAST); + PLAYER = getById("player"); + PLAYER$registryId = getRegistryId(PLAYER); + ARROW = getById("arrow"); + ARROW$registryId = getRegistryId(ARROW); + SPECTRAL_ARROW = getById("spectral_arrow"); + SPECTRAL_ARROW$registryId = getRegistryId(SPECTRAL_ARROW); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MFluids.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MFluids.java index a0412aac8..a03660080 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MFluids.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MFluids.java @@ -15,7 +15,7 @@ public final class MFluids { private static Object getById(String id) throws ReflectiveOperationException { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); - return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.FLUID, rl); + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.FLUID, rl); } static { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MItems.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MItems.java index 51fbc836b..cfe080d81 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MItems.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MItems.java @@ -1,25 +1,22 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; public final class MItems { private MItems() {} public static final Object AIR; public static final Object WATER_BUCKET; + public static final Object BARRIER; - private static Object getById(String id) throws ReflectiveOperationException { + private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); - return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.ITEM, rl); + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.ITEM, rl); } static { - try { - AIR = getById("air"); - WATER_BUCKET = getById("water_bucket"); - } catch (ReflectiveOperationException e) { - throw new ReflectionInitException("Failed to init Items", e); - } + AIR = getById("air"); + WATER_BUCKET = getById("water_bucket"); + BARRIER = getById("barrier"); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MMobEffects.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MMobEffects.java index 380fcbf1a..35bd99cd2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MMobEffects.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MMobEffects.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; public final class MMobEffects { private MMobEffects() {} @@ -10,19 +9,15 @@ public final class MMobEffects { public static final Object HASTE; public static final Object INVISIBILITY; - private static Object getById(String id) throws ReflectiveOperationException { + private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); - return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.MOB_EFFECT, rl); + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.MOB_EFFECT, rl); } // for 1.20.1-1.20.4 static { - try { - MINING_FATIGUE = getById("mining_fatigue"); - HASTE = getById("haste"); - INVISIBILITY = getById("invisibility"); - } catch (ReflectiveOperationException e) { - throw new ReflectionInitException("Failed to init MobEffects", e); - } + MINING_FATIGUE = getById("mining_fatigue"); + HASTE = getById("haste"); + INVISIBILITY = getById("invisibility"); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRecipeTypes.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRecipeTypes.java index 95d2feab5..5bf61bfd0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRecipeTypes.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MRecipeTypes.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; public final class MRecipeTypes { private MRecipeTypes() {} @@ -14,22 +13,18 @@ public final class MRecipeTypes { public static final Object STONECUTTING; public static final Object SMITHING; - private static Object getById(String id) throws ReflectiveOperationException { + private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); - return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.RECIPE_TYPE, rl); + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.RECIPE_TYPE, rl); } static { - try { - CRAFTING = getById("crafting"); - SMELTING = getById("smelting"); - BLASTING = getById("blasting"); - SMOKING = getById("smoking"); - CAMPFIRE_COOKING = getById("campfire_cooking"); - STONECUTTING = getById("stonecutting"); - SMITHING = getById("smithing"); - } catch (ReflectiveOperationException e) { - throw new ReflectionInitException("Failed to init RecipeTypes", e); - } + CRAFTING = getById("crafting"); + SMELTING = getById("smelting"); + BLASTING = getById("blasting"); + SMOKING = getById("smoking"); + CAMPFIRE_COOKING = getById("campfire_cooking"); + STONECUTTING = getById("stonecutting"); + SMITHING = getById("smithing"); } } 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 244d26904..ad3d3f545 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 @@ -23,6 +23,8 @@ public final class MRegistries { public static final Object DIMENSION_TYPE; public static final Object CONFIGURED_FEATURE; public static final Object PLACED_FEATURE; + public static final Object TRIM_PATTERN; + public static final Object TRIM_MATERIAL; @Nullable // 1.21+ public static final Object JUKEBOX_SONG; @Nullable // 1.21+ @@ -46,6 +48,8 @@ public final class MRegistries { Object registries$PlacedFeature = null; Object registries$JukeboxSong = null; Object registries$Recipe = null; + Object registries$TrimPattern = null; + Object registries$TrimMaterial = null; for (Field field : fields) { Type fieldType = field.getGenericType(); if (fieldType instanceof ParameterizedType paramType) { @@ -87,6 +91,10 @@ public final class MRegistries { registries$JukeboxSong = field.get(null); } else if (type == CoreReflections.clazz$PlacedFeature) { registries$PlacedFeature = field.get(null); + } else if (type == CoreReflections.clazz$TrimPattern) { + registries$TrimPattern = field.get(null); + } else if (type == CoreReflections.clazz$TrimMaterial) { + registries$TrimMaterial = field.get(null); } } } @@ -106,6 +114,8 @@ public final class MRegistries { RECIPE_TYPE = requireNonNull(registries$RecipeType); CONFIGURED_FEATURE = requireNonNull(registries$ConfiguredFeature); PLACED_FEATURE = requireNonNull(registries$PlacedFeature); + TRIM_PATTERN = requireNonNull(registries$TrimPattern); + TRIM_MATERIAL = requireNonNull(registries$TrimMaterial); JUKEBOX_SONG = registries$JukeboxSong; RECIPE = registries$Recipe; } catch (ReflectiveOperationException e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MSoundEvents.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MSoundEvents.java index dbdc932e4..747dde390 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MSoundEvents.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MSoundEvents.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; public final class MSoundEvents { private MSoundEvents() {} @@ -12,20 +11,16 @@ public final class MSoundEvents { public static final Object TRIDENT_RIPTIDE_3; public static final Object TRIDENT_THROW; - private static Object getById(String id) throws ReflectiveOperationException { + private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); - return CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.SOUND_EVENT, rl); + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.SOUND_EVENT, rl); } static { - try { - EMPTY = getById("intentionally_empty"); - TRIDENT_RIPTIDE_1 = getById("item.trident_riptide_1"); - TRIDENT_RIPTIDE_2 = getById("item.trident_riptide_2"); - TRIDENT_RIPTIDE_3 = getById("item.trident.riptide_3"); - TRIDENT_THROW = getById("item.trident.throw"); - } catch (ReflectiveOperationException e) { - throw new ReflectionInitException("Failed to init SoundEvents", e); - } + EMPTY = getById("intentionally_empty"); + TRIDENT_RIPTIDE_1 = getById("item.trident_riptide_1"); + TRIDENT_RIPTIDE_2 = getById("item.trident_riptide_2"); + TRIDENT_RIPTIDE_3 = getById("item.trident.riptide_3"); + TRIDENT_THROW = getById("item.trident.throw"); } } 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 ee5530be2..9b5377f07 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 @@ -3,6 +3,7 @@ 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.MiscUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -1315,7 +1316,6 @@ public final class NetworkReflections { 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; @@ -1385,10 +1385,6 @@ public final class NetworkReflections { 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)) @@ -1497,4 +1493,105 @@ public final class NetworkReflections { throw new ReflectionInitException("Failed to initialize ParticleTypes$STREAM_CODEC", e); } } + + public static final Class clazz$ClientboundFinishConfigurationPacket = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.configuration.ClientboundFinishConfigurationPacket") + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Constructor constructor$ClientboundFinishConfigurationPacket = Optional.ofNullable(clazz$ClientboundFinishConfigurationPacket) + .map(ReflectionUtils::getConstructor) + .orElse(null); + + // 1.20.5+ + public static final Field field$ClientboundFinishConfigurationPacket$INSTANCE = Optional.ofNullable(clazz$ClientboundFinishConfigurationPacket) + .map(it -> ReflectionUtils.getDeclaredField(it, it, 0)) + .orElse(null); + + public static final Object instance$ClientboundFinishConfigurationPacket$INSTANCE; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + instance$ClientboundFinishConfigurationPacket$INSTANCE = VersionHelper.isOrAbove1_20_5() + ? field$ClientboundFinishConfigurationPacket$INSTANCE.get(null) + : constructor$ClientboundFinishConfigurationPacket.newInstance(); + } else { + instance$ClientboundFinishConfigurationPacket$INSTANCE = null; + } + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize ClientboundFinishConfigurationPacket$INSTANCE", e); + } + } + + public static final Class clazz$ServerCommonPacketListener = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerCommonPacketListener") + ), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.2+ + public static final Method method$ServerCommonPacketListener$handleResourcePackResponse = Optional.ofNullable(clazz$ServerCommonPacketListener) + .map(it -> ReflectionUtils.getMethod(it, void.class, clazz$ServerboundResourcePackPacket)) + .orElse(null); + + public static final MethodHandle methodHandle$ServerCommonPacketListener$handleResourcePackResponse; + + static { + try { + if (VersionHelper.isOrAbove1_20_2()) { + methodHandle$ServerCommonPacketListener$handleResourcePackResponse = + ReflectionUtils.unreflectMethod(method$ServerCommonPacketListener$handleResourcePackResponse) + .asType(MethodType.methodType(void.class, Object.class, Object.class)); + } else { + methodHandle$ServerCommonPacketListener$handleResourcePackResponse = null; + } + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize ServerCommonPacketListener$handleResourcePackResponse", e); + } + } + + public static final Class clazz$ClientboundLoginFinishedPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.login.PacketLoginOutSuccess", + List.of("network.protocol.login.ClientboundLoginFinishedPacket", "network.protocol.login.ClientboundGameProfilePacket") + ) + ); + + public static final Class clazz$ClientboundRecipeBookAddPacket = MiscUtils.requireNonNullIf(BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.ClientboundRecipeBookAddPacket", + "network.protocol.game.ClientboundRecipeBookAddPacket" + ), VersionHelper.isOrAbove1_21_2()); + + public static final Class clazz$ClientboundPlaceGhostRecipePacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayOutAutoRecipe", + "network.protocol.game.ClientboundPlaceGhostRecipePacket" + ) + ); + + public static final Class clazz$ClientboundUpdateRecipesPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayOutRecipeUpdate", + "network.protocol.game.ClientboundUpdateRecipesPacket" + ) + ); + + public static final Class clazz$ClientboundUpdateAdvancementsPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayOutAdvancements", + "network.protocol.game.ClientboundUpdateAdvancementsPacket" + ) + ); + + public static final Class clazz$ClientboundUpdateTagsPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + List.of("network.protocol.common.ClientboundUpdateTagsPacket", "network.protocol.game.PacketPlayOutTags"), + List.of("network.protocol.common.ClientboundUpdateTagsPacket", "network.protocol.game.ClientboundUpdateTagsPacket") + ) + ); } 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 74078791f..a6be8c3b8 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 @@ -29,7 +29,6 @@ import net.momirealms.craftengine.core.plugin.config.Config; 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; @@ -48,6 +47,7 @@ import org.bukkit.persistence.PersistentDataType; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.util.RayTraceResult; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -58,8 +58,7 @@ import java.util.concurrent.ConcurrentHashMap; public class BukkitServerPlayer extends Player { private final BukkitCraftEngine plugin; - // handshake - private ProtocolVersion protocolVersion = ProtocolVersion.UNKNOWN; + // connection state private final Channel channel; private ChannelHandler connection; @@ -67,8 +66,8 @@ public class BukkitServerPlayer extends Player { private UUID uuid; private ConnectionState decoderState; private ConnectionState encoderState; + private boolean shouldProcessFinishConfiguration = true; private final Set resourcePackUUID = Collections.synchronizedSet(new HashSet<>()); - private boolean sentResourcePack = !Config.sendPackOnJoin(); // some references private Reference playerRef; private Reference serverPlayerRef; @@ -252,13 +251,8 @@ public class BukkitServerPlayer extends Player { @Override public boolean canInstabuild() { - try { - Object abilities = CoreReflections.field$Player$abilities.get(serverPlayer()); - return (boolean) CoreReflections.field$Abilities$instabuild.get(abilities); - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to get canInstabuild for " + name(), e); - return false; - } + Object abilities = FastNMS.INSTANCE.field$Player$abilities(serverPlayer()); + return FastNMS.INSTANCE.field$Abilities$instabuild(abilities); } @Override @@ -600,7 +594,7 @@ public class BukkitServerPlayer extends Player { CoreReflections.field$ServerPlayerGameMode$isDestroyingBlock.set(gameMode, false); // check item in hand Item item = this.getItemInHand(InteractionHand.MAIN_HAND); - if (item != null) { + if (!item.isEmpty()) { Material itemMaterial = item.getItem().getType(); // creative mode + invalid item in hand if (canInstabuild() && (itemMaterial == Material.DEBUG_STICK @@ -618,7 +612,7 @@ public class BukkitServerPlayer extends Player { ImmutableBlockState customState = optionalCustomState.get(); BlockSettings blockSettings = customState.settings(); if (blockSettings.requireCorrectTool()) { - if (item != null) { + if (!item.isEmpty()) { // it's correct on plugin side if (blockSettings.isCorrectTool(item.id())) { // but not on serverside @@ -770,7 +764,7 @@ public class BukkitServerPlayer extends Player { return DirectionUtils.toDirection(platformPlayer().getFacing()); } - @Nullable + @NotNull @Override public Item getItemInHand(InteractionHand hand) { PlayerInventory inventory = platformPlayer().getInventory(); @@ -874,23 +868,18 @@ public class BukkitServerPlayer extends Player { } @Override - public ProtocolVersion protocolVersion() { - return this.protocolVersion; + public boolean isResourcePackLoading(UUID uuid) { + return this.resourcePackUUID.contains(uuid); } @Override - public void setProtocolVersion(int protocolVersion) { - this.protocolVersion = ProtocolVersion.getById(protocolVersion); + public void setShouldProcessFinishConfiguration(boolean shouldProcess) { + this.shouldProcessFinishConfiguration = shouldProcess; } @Override - public boolean sentResourcePack() { - return this.sentResourcePack; - } - - @Override - public void setSentResourcePack(boolean sentResourcePack) { - this.sentResourcePack = sentResourcePack; + public boolean shouldProcessFinishConfiguration() { + return this.shouldProcessFinishConfiguration; } @Override 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 ffc9dab4c..dce7ca633 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 @@ -29,21 +29,23 @@ public class BukkitSoundManager extends AbstractSoundManager { @Override protected void registerSongs(Map songs) { if (songs.isEmpty()) return; + Object registry = FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(FastNMS.INSTANCE.registryAccess(), MRegistries.JUKEBOX_SONG); try { - Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.JUKEBOX_SONG);; - unfreezeRegistry(registry); + // 获取 JUKEBOX_SONG 注册表 + CoreReflections.field$MappedRegistry$frozen.set(registry, false); for (Map.Entry entry : songs.entrySet()) { Key id = entry.getKey(); JukeboxSong jukeboxSong = entry.getValue(); Object resourceLocation = KeyUtils.toResourceLocation(id); Object soundId = KeyUtils.toResourceLocation(jukeboxSong.sound()); - Object song = CoreReflections.method$Registry$get.invoke(registry, resourceLocation); + // 检查之前有没有注册过了 + Object song = FastNMS.INSTANCE.method$Registry$getValue(registry, resourceLocation); Object soundEvent = VersionHelper.isOrAbove1_21_2() ? CoreReflections.constructor$SoundEvent.newInstance(soundId, Optional.of(jukeboxSong.range())) : CoreReflections.constructor$SoundEvent.newInstance(soundId, jukeboxSong.range(), false); Object soundHolder = CoreReflections.method$Holder$direct.invoke(null, soundEvent); - + // 只有没注册才注册,否则会报错 if (song == null) { song = CoreReflections.constructor$JukeboxSong.newInstance(soundHolder, ComponentUtils.adventureToMinecraft(jukeboxSong.description()), jukeboxSong.lengthInSeconds(), jukeboxSong.comparatorOutput()); Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, song); @@ -51,17 +53,12 @@ public class BukkitSoundManager extends AbstractSoundManager { CoreReflections.field$Holder$Reference$tags.set(holder, Set.of()); } } - freezeRegistry(registry); } catch (Exception e) { - plugin.logger().warn("Failed to register jukebox songs.", e); + this.plugin.logger().warn("Failed to register jukebox songs.", e); + } finally { + try { + CoreReflections.field$MappedRegistry$frozen.set(registry, true); + } catch (ReflectiveOperationException ignored) {} } } - - private void unfreezeRegistry(Object registry) throws IllegalAccessException { - CoreReflections.field$MappedRegistry$frozen.set(registry, false); - } - - private void freezeRegistry(Object registry) throws IllegalAccessException { - CoreReflections.field$MappedRegistry$frozen.set(registry, true); - } } 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 444aa1d65..e575d2f20 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 @@ -50,11 +50,9 @@ public class BlockStateUtils { public static boolean isCorrectTool(@NotNull ImmutableBlockState state, @Nullable Item itemInHand) { BlockSettings settings = state.settings(); if (settings.requireCorrectTool()) { - if (itemInHand == null) return false; - if (!settings.isCorrectTool(itemInHand.id()) && - (!settings.respectToolComponent() || !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(itemInHand.getLiteralObject(), state.customBlockState().handle()))) { - return false; - } + if (itemInHand == null || itemInHand.isEmpty()) return false; + return settings.isCorrectTool(itemInHand.id()) || + (settings.respectToolComponent() && FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(itemInHand.getLiteralObject(), state.customBlockState().handle())); } return true; } @@ -62,7 +60,7 @@ public class BlockStateUtils { @SuppressWarnings("unchecked") public static List getAllVanillaBlockStates(Key block) { try { - Object blockIns = CoreReflections.method$Registry$get.invoke(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(block)); + Object blockIns = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(block)); Object definition = CoreReflections.field$Block$StateDefinition.get(blockIns); return (List) CoreReflections.field$StateDefinition$states.get(definition); } catch (Exception e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java index 715c28741..d2c342de1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityDataUtils.java @@ -16,6 +16,7 @@ public class EntityDataUtils { public static final int DISPLAYED_ITEM_DATA_ID = VersionHelper.isOrAbove1_20_2() ? 23 : 22; public static final int CUSTOM_NAME_DATA_ID = 2; public static final int ITEM_DATA_ID = 8; + public static final int ITEM_FRAME_DATA_ID = VersionHelper.isOrAbove1_21_6() ? 9 : 8; public static byte encodeTextDisplayMask(boolean hasShadow, boolean isSeeThrough, boolean useDefaultBackground, int alignment) { int bitMask = 0; 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 345d00e01..11f5213b8 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 @@ -4,13 +4,11 @@ import net.momirealms.craftengine.bukkit.item.recipe.BukkitRecipeManager; import net.momirealms.craftengine.core.block.BlockKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemKeys; -import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.QuadFunction; @@ -20,10 +18,10 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Bell; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; -import java.util.Optional; public class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); @@ -80,17 +78,15 @@ public class InteractUtils { }); registerInteraction(BlockKeys.SOUL_CAMPFIRE, (player, item, blockState, result) -> { if (!Config.enableRecipeSystem()) return false; - Optional> optional = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(item.id()); - return optional.filter(keyReference -> BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( - keyReference, item.getItem() - ))) != null).isPresent(); + return BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new UniqueIdItem<>( + item.recipeIngredientId(), item + ))) != null; }); registerInteraction(BlockKeys.CAMPFIRE, (player, item, blockState, result) -> { if (!Config.enableRecipeSystem()) return false; - Optional> optional = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(item.id()); - return optional.filter(keyReference -> BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( - keyReference, item.getItem() - ))) != null).isPresent(); + return BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new UniqueIdItem<>( + item.recipeIngredientId(), item + ))) != null; }); registerInteraction(BlockKeys.DECORATED_POT, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.HOPPER, (player, item, blockState, result) -> true); @@ -130,6 +126,10 @@ public class InteractUtils { registerInteraction(BlockKeys.PALE_OAK_BUTTON, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.MANGROVE_BUTTON, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.BAMBOO_BUTTON, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.STONE_BUTTON, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.POLISHED_BLACKSTONE_BUTTON, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.CRIMSON_BUTTON, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.WARPED_BUTTON, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.OAK_TRAPDOOR, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.SPRUCE_TRAPDOOR, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.BIRCH_TRAPDOOR, (player, item, blockState, result) -> true); @@ -288,7 +288,7 @@ public class InteractUtils { } } - public static boolean isInteractable(Player player, BlockData state, BlockHitResult hit, Item item) { + public static boolean isInteractable(Player player, BlockData state, BlockHitResult hit, @Nullable Item item) { Key blockType = BlockStateUtils.getBlockOwnerIdFromData(state); if (INTERACTIONS.containsKey(blockType)) { return INTERACTIONS.get(blockType).apply(player, item, state, hit); @@ -297,7 +297,7 @@ public class InteractUtils { } } - public static boolean willConsume(Player player, BlockData state, BlockHitResult hit, Item item) { + public static boolean willConsume(Player player, BlockData state, BlockHitResult hit, @Nullable Item item) { if (item == null) return false; Key blockType = BlockStateUtils.getBlockOwnerIdFromData(state); if (WILL_CONSUME.containsKey(blockType)) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InventoryUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InventoryUtils.java index c6ade8fe1..49192e90c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InventoryUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InventoryUtils.java @@ -1,5 +1,8 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; @@ -7,20 +10,28 @@ public class InventoryUtils { private InventoryUtils() {} + public static Player getPlayerFromInventoryEvent(InventoryEvent event) { + if (VersionHelper.isOrAbove1_21()) { + return (Player) event.getView().getPlayer(); + } else { + return LegacyInventoryUtils.getPlayerFromInventoryEvent(event); + } + } + public static int getSuitableHotBarSlot(PlayerInventory inventory) { int selectedSlot = inventory.getHeldItemSlot(); int i; int j; for (j = 0; j < 9; ++j) { i = (selectedSlot + j) % 9; - if (ItemUtils.isEmpty(inventory.getItem(i))) { + if (ItemStackUtils.isEmpty(inventory.getItem(i))) { return i; } } for (j = 0; j < 9; ++j) { i = (selectedSlot + j) % 9; ItemStack item = inventory.getItem(i); - if (ItemUtils.isEmpty(item) || item.getEnchantments().isEmpty()) { + if (ItemStackUtils.isEmpty(item) || item.getEnchantments().isEmpty()) { return i; } } @@ -31,7 +42,7 @@ public class InventoryUtils { ItemStack[] items = inventory.getStorageContents(); for (int i = 0; i < items.length; ++i) { ItemStack stack = items[i]; - if (ItemUtils.isEmpty(stack)) continue; + if (ItemStackUtils.isEmpty(stack)) continue; if (stack.isSimilar(itemStack)) { return i; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java similarity index 89% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemUtils.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java index 2c6704e9a..1ade133c7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemStackUtils.java @@ -7,9 +7,9 @@ import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; -public class ItemUtils { +public class ItemStackUtils { - private ItemUtils() {} + private ItemStackUtils() {} @Contract("null -> true") public static boolean isEmpty(final ItemStack item) { @@ -20,7 +20,7 @@ public class ItemUtils { public static boolean hasCustomItem(ItemStack[] stack) { for (ItemStack itemStack : stack) { - if (!ItemUtils.isEmpty(itemStack)) { + if (!ItemStackUtils.isEmpty(itemStack)) { if (BukkitItemManager.instance().wrap(itemStack).customId().isPresent()) { return true; } @@ -30,7 +30,7 @@ public class ItemUtils { } public static boolean isCustomItem(ItemStack stack) { - if (!ItemUtils.isEmpty(stack)) { + if (!ItemStackUtils.isEmpty(stack)) { return BukkitItemManager.instance().wrap(stack).customId().isPresent(); } return false; 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 2e972673e..1f35e3e90 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 @@ -1,6 +1,6 @@ package net.momirealms.craftengine.bukkit.util; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; import net.momirealms.craftengine.core.util.Key; @@ -18,15 +18,9 @@ public class ItemTags { public static Object getOrCreate(Key key) { Object value = CACHE.get(key); if (value == null) { - try { - value = CoreReflections.method$TagKey$create.invoke(null, MRegistries.ITEM, KeyUtils.toResourceLocation(key)); - CACHE.put(key, value); - return value; - } catch (Exception e) { - throw new RuntimeException("Failed to create block tag: " + key, e); - } - } else { - return value; + value = FastNMS.INSTANCE.method$TagKey$create(MRegistries.ITEM, KeyUtils.toResourceLocation(key)); + CACHE.put(key, value); } + return value; } } 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 f6e8bf219..0e53d5748 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.BIOME)); + Object idMap = CoreReflections.method$Registry$asHolderIdMap.invoke(FastNMS.INSTANCE.method$RegistryAccess$lookupOrThrow(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/util/ResourcePackUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ResourcePackUtils.java index 8d15638b3..cbfb26b86 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ResourcePackUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ResourcePackUtils.java @@ -5,9 +5,14 @@ import net.momirealms.craftengine.core.plugin.config.Config; import java.util.UUID; -public class ResourcePackUtils { +public final class ResourcePackUtils { + private ResourcePackUtils() {} public static Object createPacket(UUID uuid, String url, String hash) { return FastNMS.INSTANCE.constructor$ClientboundResourcePackPushPacket(uuid, url, hash, Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt())); } + + public static Object createServerResourcePackInfo(UUID uuid, String url, String hash) { + return FastNMS.INSTANCE.constructor$ServerResourcePackInfo(uuid, url, hash, Config.kickOnDeclined(), ComponentUtils.adventureToMinecraft(Config.resourcePackPrompt())); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java index 6b4a3bb01..170c50dd1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitBlockInWorld.java @@ -32,7 +32,7 @@ public class BukkitBlockInWorld implements BlockInWorld { public boolean isWaterSource(BlockPlaceContext blockPlaceContext) { Location location = this.block.getLocation(); Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.block.getWorld()); - Object fluidData = FastNMS.INSTANCE.method$Level$getFluidState(serverLevel, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ())); + Object fluidData = FastNMS.INSTANCE.method$BlockGetter$getFluidState(serverLevel, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ())); if (fluidData == null) return false; return FastNMS.INSTANCE.method$FluidState$getType(fluidData) == MFluids.WATER; } 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 ff28dbf29..af2d6c269 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 @@ -72,7 +72,7 @@ public class BukkitWorld implements World { @Override public void dropItemNaturally(Position location, Item item) { ItemStack itemStack = (ItemStack) item.getItem(); - if (ItemUtils.isEmpty(itemStack)) return; + if (ItemStackUtils.isEmpty(itemStack)) return; if (VersionHelper.isOrAbove1_21_2()) { platformWorld().dropItemNaturally(new Location(null, location.x(), location.y(), location.z()), (ItemStack) item.getItem()); } else { @@ -121,6 +121,6 @@ public class BukkitWorld implements World { @Override public void levelEvent(int id, BlockPos pos, int data) { - FastNMS.INSTANCE.method$Level$levelEvent(serverWorld(), id, LocationUtils.toBlockPos(pos), data); + FastNMS.INSTANCE.method$LevelAccessor$levelEvent(serverWorld(), id, LocationUtils.toBlockPos(pos), data); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index 33fd76243..61aa6dabb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -277,7 +277,6 @@ public class BukkitWorldManager implements WorldManager, Listener { if (ceChunk != null) { if (ceChunk.dirty()) { try { - this.plugin.debug(() -> "[Dirty Chunk]" + pos + " unloaded"); world.worldDataStorage().writeChunkAt(pos, ceChunk); ceChunk.setDirty(false); } catch (IOException e) { diff --git a/common-files/src/main/resources/commands.yml b/common-files/src/main/resources/commands.yml index f46602c17..3ac0d8c5c 100644 --- a/common-files/src/main/resources/commands.yml +++ b/common-files/src/main/resources/commands.yml @@ -196,6 +196,13 @@ debug_is_chunk_persistent_loaded: - /craftengine debug is-chunk-persistent-loaded - /ce debug is-chunk-persistent-loaded +debug_entity_id: + enable: true + permission: ce.command.debug.debug_entity_id + usage: + - /craftengine debug entity-id + - /ce debug entity-id + 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 3c0309030..06eb8285b 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -1,7 +1,5 @@ # Do not modify this value config-version: '${config_version}' -# Enables or disables debug mode -debug: false # Enables or disables metrics collection via BStats metrics: true # Enables automatic update checks @@ -76,9 +74,8 @@ resource-pack: # Send the resource pack on joining the server send-on-join: true kick-if-declined: true - prompt: | - To fully experience our server, - please accept our custom resource pack. + kick-if-failed-to-apply: true + prompt: "To fully experience our server,please accept our custom resource pack." # If you are hosting the resource pack by yourself, replace `localhost` with your server ip otherwise it would only work on your local pc # If using BungeeCord or Velocity, consider using a proxy-side plugin to handle resource pack delivery. # Read this page for more host types: https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host @@ -139,9 +136,22 @@ resource-pack: type: merge_atlas item: - # Add a tag on item name and lore + # Make custom-model-data and item-model clientside by default + client-bound-model: false + # Add a tag on custom name and lore non-italic-tag: false +equipment: + # The sacrificed-vanilla-armor argument determines which vanilla armor gets completely removed (loses all its trims) + # when you create new armor using trim types, freeing up a slot for your custom armor. + sacrificed-vanilla-armor: + type: chainmail + # CraftEngine repurposes a vanilla armor's texture slot for custom armor trims. + # To preserve the original look, it uses trim configurations to reconstruct the default appearance. + asset-id: minecraft:chainmail + humanoid: minecraft:trims/entity/humanoid/chainmail + humanoid-leggings: minecraft:trims/entity/humanoid_leggings/chainmail + block: # Enables the sound system, which prevents the client from hearing some non-custom block sounds and improves the client experience. sound-system: @@ -211,7 +221,7 @@ image: intercept-packets: system-chat: true tab-list: true # Tab list header and footer - player-info: true # User list in tab + player-info: true # Player list in tab set-score: true actionbar: true title: true @@ -223,6 +233,7 @@ image: armor-stand: true # Legacy Holograms text-display: true # Modern Holograms item: true + advancement: true # Defines Unicode characters used for positioning # - Must match the font defined in resource packs # - Do NOT modify unless you understand text rendering mechanics @@ -395,4 +406,12 @@ chunk-system: # When you edit a map locally using CraftEngine fabric mod, the custom block data is not immediately synchronized with the # server's CraftEngine internal data. Enabling this option will synchronize the data when the chunk is loaded. # (This option only slightly impacts performance, which has been fully optimized, so you don't need to worry too much.) - sync-custom-blocks-on-chunk-load: false \ No newline at end of file + sync-custom-blocks-on-chunk-load: false + +# Enables or disables debug mode +debug: + common: false + packet: false + furniture: false + item: false + resource-pack: false \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/_all.json b/common-files/src/main/resources/internal/atlases/_all.json new file mode 100644 index 000000000..6f8de5a3e --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/_all.json @@ -0,0 +1 @@ +{"armor_trims":{"sources":[{"type":"minecraft:paletted_permutations","palette_key":"minecraft:trims/color_palettes/trim_palette","permutations":{"amethyst":"minecraft:trims/color_palettes/amethyst","copper":"minecraft:trims/color_palettes/copper","diamond":"minecraft:trims/color_palettes/diamond","diamond_darker":"minecraft:trims/color_palettes/diamond_darker","emerald":"minecraft:trims/color_palettes/emerald","gold":"minecraft:trims/color_palettes/gold","gold_darker":"minecraft:trims/color_palettes/gold_darker","iron":"minecraft:trims/color_palettes/iron","iron_darker":"minecraft:trims/color_palettes/iron_darker","lapis":"minecraft:trims/color_palettes/lapis","netherite":"minecraft:trims/color_palettes/netherite","netherite_darker":"minecraft:trims/color_palettes/netherite_darker","quartz":"minecraft:trims/color_palettes/quartz","redstone":"minecraft:trims/color_palettes/redstone","resin":"minecraft:trims/color_palettes/resin"},"textures":["minecraft:trims/entity/humanoid/sentry","minecraft:trims/entity/humanoid_leggings/sentry","minecraft:trims/entity/humanoid/dune","minecraft:trims/entity/humanoid_leggings/dune","minecraft:trims/entity/humanoid/coast","minecraft:trims/entity/humanoid_leggings/coast","minecraft:trims/entity/humanoid/wild","minecraft:trims/entity/humanoid_leggings/wild","minecraft:trims/entity/humanoid/ward","minecraft:trims/entity/humanoid_leggings/ward","minecraft:trims/entity/humanoid/eye","minecraft:trims/entity/humanoid_leggings/eye","minecraft:trims/entity/humanoid/vex","minecraft:trims/entity/humanoid_leggings/vex","minecraft:trims/entity/humanoid/tide","minecraft:trims/entity/humanoid_leggings/tide","minecraft:trims/entity/humanoid/snout","minecraft:trims/entity/humanoid_leggings/snout","minecraft:trims/entity/humanoid/rib","minecraft:trims/entity/humanoid_leggings/rib","minecraft:trims/entity/humanoid/spire","minecraft:trims/entity/humanoid_leggings/spire","minecraft:trims/entity/humanoid/wayfinder","minecraft:trims/entity/humanoid_leggings/wayfinder","minecraft:trims/entity/humanoid/shaper","minecraft:trims/entity/humanoid_leggings/shaper","minecraft:trims/entity/humanoid/silence","minecraft:trims/entity/humanoid_leggings/silence","minecraft:trims/entity/humanoid/raiser","minecraft:trims/entity/humanoid_leggings/raiser","minecraft:trims/entity/humanoid/host","minecraft:trims/entity/humanoid_leggings/host","minecraft:trims/entity/humanoid/flow","minecraft:trims/entity/humanoid_leggings/flow","minecraft:trims/entity/humanoid/bolt","minecraft:trims/entity/humanoid_leggings/bolt"]}]},"banner_patterns":{"sources":[{"type":"minecraft:single","resource":"minecraft:entity/banner_base"},{"type":"minecraft:directory","prefix":"entity/banner/","source":"entity/banner"}]},"beds":{"sources":[{"type":"minecraft:directory","prefix":"entity/bed/","source":"entity/bed"}]},"blocks":{"sources":[{"type":"minecraft:directory","prefix":"block/","source":"block"},{"type":"minecraft:directory","prefix":"item/","source":"item"},{"type":"minecraft:directory","prefix":"entity/conduit/","source":"entity/conduit"},{"type":"minecraft:single","resource":"minecraft:entity/bell/bell_body"},{"type":"minecraft:single","resource":"minecraft:entity/decorated_pot/decorated_pot_side"},{"type":"minecraft:single","resource":"minecraft:entity/enchanting_table_book"},{"type":"minecraft:paletted_permutations","palette_key":"minecraft:trims/color_palettes/trim_palette","permutations":{"amethyst":"minecraft:trims/color_palettes/amethyst","copper":"minecraft:trims/color_palettes/copper","diamond":"minecraft:trims/color_palettes/diamond","diamond_darker":"minecraft:trims/color_palettes/diamond_darker","emerald":"minecraft:trims/color_palettes/emerald","gold":"minecraft:trims/color_palettes/gold","gold_darker":"minecraft:trims/color_palettes/gold_darker","iron":"minecraft:trims/color_palettes/iron","iron_darker":"minecraft:trims/color_palettes/iron_darker","lapis":"minecraft:trims/color_palettes/lapis","netherite":"minecraft:trims/color_palettes/netherite","netherite_darker":"minecraft:trims/color_palettes/netherite_darker","quartz":"minecraft:trims/color_palettes/quartz","redstone":"minecraft:trims/color_palettes/redstone","resin":"minecraft:trims/color_palettes/resin"},"textures":["minecraft:trims/items/helmet_trim","minecraft:trims/items/chestplate_trim","minecraft:trims/items/leggings_trim","minecraft:trims/items/boots_trim"]}]},"chests":{"sources":[{"type":"minecraft:directory","prefix":"entity/chest/","source":"entity/chest"}]},"decorated_pot":{"sources":[{"type":"minecraft:directory","prefix":"entity/decorated_pot/","source":"entity/decorated_pot"}]},"gui":{"sources":[{"type":"minecraft:directory","prefix":"","source":"gui/sprites"},{"type":"minecraft:directory","prefix":"mob_effect/","source":"mob_effect"}]},"map_decorations":{"sources":[{"type":"minecraft:directory","prefix":"","source":"map/decorations"}]},"paintings":{"sources":[{"type":"minecraft:directory","prefix":"","source":"painting"}]},"particles":{"sources":[{"type":"minecraft:directory","prefix":"","source":"particle"}]},"shield_patterns":{"sources":[{"type":"minecraft:single","resource":"minecraft:entity/shield_base"},{"type":"minecraft:single","resource":"minecraft:entity/shield_base_nopattern"},{"type":"minecraft:directory","prefix":"entity/shield/","source":"entity/shield"}]},"shulker_boxes":{"sources":[{"type":"minecraft:directory","prefix":"entity/shulker/","source":"entity/shulker"}]},"signs":{"sources":[{"type":"minecraft:directory","prefix":"entity/signs/","source":"entity/signs"}]}} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/_list.json b/common-files/src/main/resources/internal/atlases/_list.json new file mode 100644 index 000000000..5e3c3a0f3 --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["armor_trims.json","banner_patterns.json","beds.json","blocks.json","chests.json","decorated_pot.json","gui.json","map_decorations.json","paintings.json","particles.json","shield_patterns.json","shulker_boxes.json","signs.json"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/armor_trims.json b/common-files/src/main/resources/internal/atlases/armor_trims.json new file mode 100644 index 000000000..7e92af33f --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/armor_trims.json @@ -0,0 +1,63 @@ +{ + "sources": [ + { + "type": "minecraft:paletted_permutations", + "palette_key": "minecraft:trims/color_palettes/trim_palette", + "permutations": { + "amethyst": "minecraft:trims/color_palettes/amethyst", + "copper": "minecraft:trims/color_palettes/copper", + "diamond": "minecraft:trims/color_palettes/diamond", + "diamond_darker": "minecraft:trims/color_palettes/diamond_darker", + "emerald": "minecraft:trims/color_palettes/emerald", + "gold": "minecraft:trims/color_palettes/gold", + "gold_darker": "minecraft:trims/color_palettes/gold_darker", + "iron": "minecraft:trims/color_palettes/iron", + "iron_darker": "minecraft:trims/color_palettes/iron_darker", + "lapis": "minecraft:trims/color_palettes/lapis", + "netherite": "minecraft:trims/color_palettes/netherite", + "netherite_darker": "minecraft:trims/color_palettes/netherite_darker", + "quartz": "minecraft:trims/color_palettes/quartz", + "redstone": "minecraft:trims/color_palettes/redstone", + "resin": "minecraft:trims/color_palettes/resin" + }, + "textures": [ + "minecraft:trims/entity/humanoid/sentry", + "minecraft:trims/entity/humanoid_leggings/sentry", + "minecraft:trims/entity/humanoid/dune", + "minecraft:trims/entity/humanoid_leggings/dune", + "minecraft:trims/entity/humanoid/coast", + "minecraft:trims/entity/humanoid_leggings/coast", + "minecraft:trims/entity/humanoid/wild", + "minecraft:trims/entity/humanoid_leggings/wild", + "minecraft:trims/entity/humanoid/ward", + "minecraft:trims/entity/humanoid_leggings/ward", + "minecraft:trims/entity/humanoid/eye", + "minecraft:trims/entity/humanoid_leggings/eye", + "minecraft:trims/entity/humanoid/vex", + "minecraft:trims/entity/humanoid_leggings/vex", + "minecraft:trims/entity/humanoid/tide", + "minecraft:trims/entity/humanoid_leggings/tide", + "minecraft:trims/entity/humanoid/snout", + "minecraft:trims/entity/humanoid_leggings/snout", + "minecraft:trims/entity/humanoid/rib", + "minecraft:trims/entity/humanoid_leggings/rib", + "minecraft:trims/entity/humanoid/spire", + "minecraft:trims/entity/humanoid_leggings/spire", + "minecraft:trims/entity/humanoid/wayfinder", + "minecraft:trims/entity/humanoid_leggings/wayfinder", + "minecraft:trims/entity/humanoid/shaper", + "minecraft:trims/entity/humanoid_leggings/shaper", + "minecraft:trims/entity/humanoid/silence", + "minecraft:trims/entity/humanoid_leggings/silence", + "minecraft:trims/entity/humanoid/raiser", + "minecraft:trims/entity/humanoid_leggings/raiser", + "minecraft:trims/entity/humanoid/host", + "minecraft:trims/entity/humanoid_leggings/host", + "minecraft:trims/entity/humanoid/flow", + "minecraft:trims/entity/humanoid_leggings/flow", + "minecraft:trims/entity/humanoid/bolt", + "minecraft:trims/entity/humanoid_leggings/bolt" + ] + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/banner_patterns.json b/common-files/src/main/resources/internal/atlases/banner_patterns.json new file mode 100644 index 000000000..b683a9828 --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/banner_patterns.json @@ -0,0 +1,13 @@ +{ + "sources": [ + { + "type": "minecraft:single", + "resource": "minecraft:entity/banner_base" + }, + { + "type": "minecraft:directory", + "prefix": "entity/banner/", + "source": "entity/banner" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/beds.json b/common-files/src/main/resources/internal/atlases/beds.json new file mode 100644 index 000000000..d2e798a5e --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/beds.json @@ -0,0 +1,9 @@ +{ + "sources": [ + { + "type": "minecraft:directory", + "prefix": "entity/bed/", + "source": "entity/bed" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/chests.json b/common-files/src/main/resources/internal/atlases/chests.json new file mode 100644 index 000000000..81a68b1ca --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/chests.json @@ -0,0 +1,9 @@ +{ + "sources": [ + { + "type": "minecraft:directory", + "prefix": "entity/chest/", + "source": "entity/chest" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/decorated_pot.json b/common-files/src/main/resources/internal/atlases/decorated_pot.json new file mode 100644 index 000000000..57356d985 --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/decorated_pot.json @@ -0,0 +1,9 @@ +{ + "sources": [ + { + "type": "minecraft:directory", + "prefix": "entity/decorated_pot/", + "source": "entity/decorated_pot" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/gui.json b/common-files/src/main/resources/internal/atlases/gui.json new file mode 100644 index 000000000..1ad438f00 --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/gui.json @@ -0,0 +1,14 @@ +{ + "sources": [ + { + "type": "minecraft:directory", + "prefix": "", + "source": "gui/sprites" + }, + { + "type": "minecraft:directory", + "prefix": "mob_effect/", + "source": "mob_effect" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/map_decorations.json b/common-files/src/main/resources/internal/atlases/map_decorations.json new file mode 100644 index 000000000..f5cf7910d --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/map_decorations.json @@ -0,0 +1,9 @@ +{ + "sources": [ + { + "type": "minecraft:directory", + "prefix": "", + "source": "map/decorations" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/paintings.json b/common-files/src/main/resources/internal/atlases/paintings.json new file mode 100644 index 000000000..1345d6d1e --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/paintings.json @@ -0,0 +1,9 @@ +{ + "sources": [ + { + "type": "minecraft:directory", + "prefix": "", + "source": "painting" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/particles.json b/common-files/src/main/resources/internal/atlases/particles.json new file mode 100644 index 000000000..18229aff0 --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/particles.json @@ -0,0 +1,9 @@ +{ + "sources": [ + { + "type": "minecraft:directory", + "prefix": "", + "source": "particle" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/shield_patterns.json b/common-files/src/main/resources/internal/atlases/shield_patterns.json new file mode 100644 index 000000000..77793ed1b --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/shield_patterns.json @@ -0,0 +1,17 @@ +{ + "sources": [ + { + "type": "minecraft:single", + "resource": "minecraft:entity/shield_base" + }, + { + "type": "minecraft:single", + "resource": "minecraft:entity/shield_base_nopattern" + }, + { + "type": "minecraft:directory", + "prefix": "entity/shield/", + "source": "entity/shield" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/shulker_boxes.json b/common-files/src/main/resources/internal/atlases/shulker_boxes.json new file mode 100644 index 000000000..d4ecef71e --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/shulker_boxes.json @@ -0,0 +1,9 @@ +{ + "sources": [ + { + "type": "minecraft:directory", + "prefix": "entity/shulker/", + "source": "entity/shulker" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/atlases/signs.json b/common-files/src/main/resources/internal/atlases/signs.json new file mode 100644 index 000000000..1f34aaa1a --- /dev/null +++ b/common-files/src/main/resources/internal/atlases/signs.json @@ -0,0 +1,9 @@ +{ + "sources": [ + { + "type": "minecraft:directory", + "prefix": "entity/signs/", + "source": "entity/signs" + } + ] +} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/models/item/_all.json b/common-files/src/main/resources/internal/models/item/_all.json index 42c70261e..7f63f8920 100644 --- a/common-files/src/main/resources/internal/models/item/_all.json +++ b/common-files/src/main/resources/internal/models/item/_all.json @@ -1 +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"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/black_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blue_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brown_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cyan_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gray_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/green_harness"}},"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]}}},"happy_ghast_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/happy_ghast_spawn_egg"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_blue_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_gray_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lime_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magenta_harness"}},"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_tears":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_tears"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/orange_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pink_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/purple_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/red_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/white_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/yellow_harness"}},"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 +{"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/black_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/blue_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/brown_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/cyan_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/gray_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/green_harness"}},"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]}}},"happy_ghast_spawn_egg":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/happy_ghast_spawn_egg"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_blue_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/light_gray_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/lime_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/magenta_harness"}},"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_lava_chicken":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_lava_chicken"}},"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_tears":{"parent":"minecraft:item/template_music_disc","textures":{"layer0":"minecraft:item/music_disc_tears"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/orange_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/pink_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/purple_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/red_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/white_harness"}},"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_harness":{"parent":"minecraft:item/generated","textures":{"layer0":"minecraft:item/yellow_harness"}},"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/internal/models/item/_list.json b/common-files/src/main/resources/internal/models/item/_list.json index 70042af05..1613a8c53 100644 --- a/common-files/src/main/resources/internal/models/item/_list.json +++ b/common-files/src/main/resources/internal/models/item/_list.json @@ -1 +1 @@ -{"directories":[],"files":["acacia_boat.json","acacia_chest_boat.json","acacia_door.json","acacia_hanging_sign.json","acacia_sapling.json","acacia_sign.json","activator_rail.json","air.json","allay_spawn_egg.json","allium.json","amethyst_bud.json","amethyst_cluster.json","amethyst_shard.json","angler_pottery_sherd.json","apple.json","archer_pottery_sherd.json","armadillo_scute.json","armadillo_spawn_egg.json","armor_stand.json","arms_up_pottery_sherd.json","arrow.json","axolotl_bucket.json","axolotl_spawn_egg.json","azure_bluet.json","baked_potato.json","bamboo.json","bamboo_chest_raft.json","bamboo_door.json","bamboo_hanging_sign.json","bamboo_raft.json","bamboo_sign.json","barrier.json","bat_spawn_egg.json","bee_spawn_egg.json","beef.json","beetroot.json","beetroot_seeds.json","beetroot_soup.json","bell.json","big_dripleaf.json","birch_boat.json","birch_chest_boat.json","birch_door.json","birch_hanging_sign.json","birch_sapling.json","birch_sign.json","black_bed.json","black_bundle.json","black_bundle_open_back.json","black_bundle_open_front.json","black_candle.json","black_dye.json","black_harness.json","black_shulker_box.json","black_stained_glass_pane.json","blade_pottery_sherd.json","blaze_powder.json","blaze_rod.json","blaze_spawn_egg.json","blue_bed.json","blue_bundle.json","blue_bundle_open_back.json","blue_bundle_open_front.json","blue_candle.json","blue_dye.json","blue_egg.json","blue_harness.json","blue_orchid.json","blue_shulker_box.json","blue_stained_glass_pane.json","bogged_spawn_egg.json","bolt_armor_trim_smithing_template.json","bone.json","bone_meal.json","book.json","bordure_indented_banner_pattern.json","bow.json","bow_pulling_0.json","bow_pulling_1.json","bow_pulling_2.json","bowl.json","brain_coral.json","brain_coral_fan.json","bread.json","breeze_rod.json","breeze_spawn_egg.json","brewer_pottery_sherd.json","brewing_stand.json","brick.json","brown_bed.json","brown_bundle.json","brown_bundle_open_back.json","brown_bundle_open_front.json","brown_candle.json","brown_dye.json","brown_egg.json","brown_harness.json","brown_mushroom.json","brown_shulker_box.json","brown_stained_glass_pane.json","brush.json","brush_brushing_0.json","brush_brushing_1.json","brush_brushing_2.json","bubble_coral.json","bubble_coral_fan.json","bucket.json","bundle.json","bundle_open_back.json","bundle_open_front.json","burn_pottery_sherd.json","bush.json","cactus_flower.json","cake.json","camel_spawn_egg.json","campfire.json","candle.json","carrot.json","carrot_on_a_stick.json","cat_spawn_egg.json","cauldron.json","cave_spider_spawn_egg.json","chain.json","chainmail_boots.json","chainmail_boots_amethyst_trim.json","chainmail_boots_copper_trim.json","chainmail_boots_diamond_trim.json","chainmail_boots_emerald_trim.json","chainmail_boots_gold_trim.json","chainmail_boots_iron_trim.json","chainmail_boots_lapis_trim.json","chainmail_boots_netherite_trim.json","chainmail_boots_quartz_trim.json","chainmail_boots_redstone_trim.json","chainmail_boots_resin_trim.json","chainmail_chestplate.json","chainmail_chestplate_amethyst_trim.json","chainmail_chestplate_copper_trim.json","chainmail_chestplate_diamond_trim.json","chainmail_chestplate_emerald_trim.json","chainmail_chestplate_gold_trim.json","chainmail_chestplate_iron_trim.json","chainmail_chestplate_lapis_trim.json","chainmail_chestplate_netherite_trim.json","chainmail_chestplate_quartz_trim.json","chainmail_chestplate_redstone_trim.json","chainmail_chestplate_resin_trim.json","chainmail_helmet.json","chainmail_helmet_amethyst_trim.json","chainmail_helmet_copper_trim.json","chainmail_helmet_diamond_trim.json","chainmail_helmet_emerald_trim.json","chainmail_helmet_gold_trim.json","chainmail_helmet_iron_trim.json","chainmail_helmet_lapis_trim.json","chainmail_helmet_netherite_trim.json","chainmail_helmet_quartz_trim.json","chainmail_helmet_redstone_trim.json","chainmail_helmet_resin_trim.json","chainmail_leggings.json","chainmail_leggings_amethyst_trim.json","chainmail_leggings_copper_trim.json","chainmail_leggings_diamond_trim.json","chainmail_leggings_emerald_trim.json","chainmail_leggings_gold_trim.json","chainmail_leggings_iron_trim.json","chainmail_leggings_lapis_trim.json","chainmail_leggings_netherite_trim.json","chainmail_leggings_quartz_trim.json","chainmail_leggings_redstone_trim.json","chainmail_leggings_resin_trim.json","charcoal.json","cherry_boat.json","cherry_chest_boat.json","cherry_door.json","cherry_hanging_sign.json","cherry_sapling.json","cherry_sign.json","chest.json","chest_minecart.json","chicken.json","chicken_spawn_egg.json","chorus_fruit.json","clay_ball.json","clock_00.json","clock_01.json","clock_02.json","clock_03.json","clock_04.json","clock_05.json","clock_06.json","clock_07.json","clock_08.json","clock_09.json","clock_10.json","clock_11.json","clock_12.json","clock_13.json","clock_14.json","clock_15.json","clock_16.json","clock_17.json","clock_18.json","clock_19.json","clock_20.json","clock_21.json","clock_22.json","clock_23.json","clock_24.json","clock_25.json","clock_26.json","clock_27.json","clock_28.json","clock_29.json","clock_30.json","clock_31.json","clock_32.json","clock_33.json","clock_34.json","clock_35.json","clock_36.json","clock_37.json","clock_38.json","clock_39.json","clock_40.json","clock_41.json","clock_42.json","clock_43.json","clock_44.json","clock_45.json","clock_46.json","clock_47.json","clock_48.json","clock_49.json","clock_50.json","clock_51.json","clock_52.json","clock_53.json","clock_54.json","clock_55.json","clock_56.json","clock_57.json","clock_58.json","clock_59.json","clock_60.json","clock_61.json","clock_62.json","clock_63.json","closed_eyeblossom.json","coal.json","coast_armor_trim_smithing_template.json","cobweb.json","cocoa_beans.json","cod.json","cod_bucket.json","cod_spawn_egg.json","command_block_minecart.json","comparator.json","compass_00.json","compass_01.json","compass_02.json","compass_03.json","compass_04.json","compass_05.json","compass_06.json","compass_07.json","compass_08.json","compass_09.json","compass_10.json","compass_11.json","compass_12.json","compass_13.json","compass_14.json","compass_15.json","compass_16.json","compass_17.json","compass_18.json","compass_19.json","compass_20.json","compass_21.json","compass_22.json","compass_23.json","compass_24.json","compass_25.json","compass_26.json","compass_27.json","compass_28.json","compass_29.json","compass_30.json","compass_31.json","conduit.json","cooked_beef.json","cooked_chicken.json","cooked_cod.json","cooked_mutton.json","cooked_porkchop.json","cooked_rabbit.json","cooked_salmon.json","cookie.json","copper_door.json","copper_ingot.json","cornflower.json","cow_spawn_egg.json","creaking_spawn_egg.json","creeper_banner_pattern.json","creeper_spawn_egg.json","crimson_door.json","crimson_fungus.json","crimson_hanging_sign.json","crimson_roots.json","crimson_sign.json","crossbow.json","crossbow_arrow.json","crossbow_firework.json","crossbow_pulling_0.json","crossbow_pulling_1.json","crossbow_pulling_2.json","cyan_bed.json","cyan_bundle.json","cyan_bundle_open_back.json","cyan_bundle_open_front.json","cyan_candle.json","cyan_dye.json","cyan_harness.json","cyan_shulker_box.json","cyan_stained_glass_pane.json","dandelion.json","danger_pottery_sherd.json","dark_oak_boat.json","dark_oak_chest_boat.json","dark_oak_door.json","dark_oak_hanging_sign.json","dark_oak_sapling.json","dark_oak_sign.json","dead_brain_coral.json","dead_brain_coral_fan.json","dead_bubble_coral.json","dead_bubble_coral_fan.json","dead_bush.json","dead_fire_coral.json","dead_fire_coral_fan.json","dead_horn_coral.json","dead_horn_coral_fan.json","dead_tube_coral.json","dead_tube_coral_fan.json","debug_stick.json","decorated_pot.json","detector_rail.json","diamond.json","diamond_axe.json","diamond_boots.json","diamond_boots_amethyst_trim.json","diamond_boots_copper_trim.json","diamond_boots_diamond_trim.json","diamond_boots_emerald_trim.json","diamond_boots_gold_trim.json","diamond_boots_iron_trim.json","diamond_boots_lapis_trim.json","diamond_boots_netherite_trim.json","diamond_boots_quartz_trim.json","diamond_boots_redstone_trim.json","diamond_boots_resin_trim.json","diamond_chestplate.json","diamond_chestplate_amethyst_trim.json","diamond_chestplate_copper_trim.json","diamond_chestplate_diamond_trim.json","diamond_chestplate_emerald_trim.json","diamond_chestplate_gold_trim.json","diamond_chestplate_iron_trim.json","diamond_chestplate_lapis_trim.json","diamond_chestplate_netherite_trim.json","diamond_chestplate_quartz_trim.json","diamond_chestplate_redstone_trim.json","diamond_chestplate_resin_trim.json","diamond_helmet.json","diamond_helmet_amethyst_trim.json","diamond_helmet_copper_trim.json","diamond_helmet_diamond_trim.json","diamond_helmet_emerald_trim.json","diamond_helmet_gold_trim.json","diamond_helmet_iron_trim.json","diamond_helmet_lapis_trim.json","diamond_helmet_netherite_trim.json","diamond_helmet_quartz_trim.json","diamond_helmet_redstone_trim.json","diamond_helmet_resin_trim.json","diamond_hoe.json","diamond_horse_armor.json","diamond_leggings.json","diamond_leggings_amethyst_trim.json","diamond_leggings_copper_trim.json","diamond_leggings_diamond_trim.json","diamond_leggings_emerald_trim.json","diamond_leggings_gold_trim.json","diamond_leggings_iron_trim.json","diamond_leggings_lapis_trim.json","diamond_leggings_netherite_trim.json","diamond_leggings_quartz_trim.json","diamond_leggings_redstone_trim.json","diamond_leggings_resin_trim.json","diamond_pickaxe.json","diamond_shovel.json","diamond_sword.json","disc_fragment_5.json","dolphin_spawn_egg.json","donkey_spawn_egg.json","dragon_breath.json","dragon_head.json","dried_kelp.json","drowned_spawn_egg.json","dune_armor_trim_smithing_template.json","echo_shard.json","egg.json","elder_guardian_spawn_egg.json","elytra.json","elytra_broken.json","emerald.json","enchanted_book.json","enchanted_golden_apple.json","end_crystal.json","ender_chest.json","ender_dragon_spawn_egg.json","ender_eye.json","ender_pearl.json","enderman_spawn_egg.json","endermite_spawn_egg.json","evoker_spawn_egg.json","experience_bottle.json","explorer_pottery_sherd.json","exposed_copper_door.json","eye_armor_trim_smithing_template.json","feather.json","fermented_spider_eye.json","fern.json","field_masoned_banner_pattern.json","filled_map.json","fire_charge.json","fire_coral.json","fire_coral_fan.json","firefly_bush.json","firework_rocket.json","firework_star.json","fishing_rod.json","fishing_rod_cast.json","flint.json","flint_and_steel.json","flow_armor_trim_smithing_template.json","flow_banner_pattern.json","flow_pottery_sherd.json","flower_banner_pattern.json","flower_pot.json","fox_spawn_egg.json","friend_pottery_sherd.json","frog_spawn_egg.json","frogspawn.json","furnace_minecart.json","generated.json","ghast_spawn_egg.json","ghast_tear.json","glass_bottle.json","glass_pane.json","glistering_melon_slice.json","globe_banner_pattern.json","glow_berries.json","glow_ink_sac.json","glow_item_frame.json","glow_lichen.json","glow_squid_spawn_egg.json","glowstone_dust.json","goat_horn.json","goat_spawn_egg.json","gold_ingot.json","gold_nugget.json","golden_apple.json","golden_axe.json","golden_boots.json","golden_boots_amethyst_trim.json","golden_boots_copper_trim.json","golden_boots_diamond_trim.json","golden_boots_emerald_trim.json","golden_boots_gold_trim.json","golden_boots_iron_trim.json","golden_boots_lapis_trim.json","golden_boots_netherite_trim.json","golden_boots_quartz_trim.json","golden_boots_redstone_trim.json","golden_boots_resin_trim.json","golden_carrot.json","golden_chestplate.json","golden_chestplate_amethyst_trim.json","golden_chestplate_copper_trim.json","golden_chestplate_diamond_trim.json","golden_chestplate_emerald_trim.json","golden_chestplate_gold_trim.json","golden_chestplate_iron_trim.json","golden_chestplate_lapis_trim.json","golden_chestplate_netherite_trim.json","golden_chestplate_quartz_trim.json","golden_chestplate_redstone_trim.json","golden_chestplate_resin_trim.json","golden_helmet.json","golden_helmet_amethyst_trim.json","golden_helmet_copper_trim.json","golden_helmet_diamond_trim.json","golden_helmet_emerald_trim.json","golden_helmet_gold_trim.json","golden_helmet_iron_trim.json","golden_helmet_lapis_trim.json","golden_helmet_netherite_trim.json","golden_helmet_quartz_trim.json","golden_helmet_redstone_trim.json","golden_helmet_resin_trim.json","golden_hoe.json","golden_horse_armor.json","golden_leggings.json","golden_leggings_amethyst_trim.json","golden_leggings_copper_trim.json","golden_leggings_diamond_trim.json","golden_leggings_emerald_trim.json","golden_leggings_gold_trim.json","golden_leggings_iron_trim.json","golden_leggings_lapis_trim.json","golden_leggings_netherite_trim.json","golden_leggings_quartz_trim.json","golden_leggings_redstone_trim.json","golden_leggings_resin_trim.json","golden_pickaxe.json","golden_shovel.json","golden_sword.json","gray_bed.json","gray_bundle.json","gray_bundle_open_back.json","gray_bundle_open_front.json","gray_candle.json","gray_dye.json","gray_harness.json","gray_shulker_box.json","gray_stained_glass_pane.json","green_bed.json","green_bundle.json","green_bundle_open_back.json","green_bundle_open_front.json","green_candle.json","green_dye.json","green_harness.json","green_shulker_box.json","green_stained_glass_pane.json","guardian_spawn_egg.json","gunpowder.json","guster_banner_pattern.json","guster_pottery_sherd.json","handheld.json","handheld_mace.json","handheld_rod.json","hanging_roots.json","happy_ghast_spawn_egg.json","heart_of_the_sea.json","heart_pottery_sherd.json","heartbreak_pottery_sherd.json","hoglin_spawn_egg.json","honey_bottle.json","honeycomb.json","hopper.json","hopper_minecart.json","horn_coral.json","horn_coral_fan.json","horse_spawn_egg.json","host_armor_trim_smithing_template.json","howl_pottery_sherd.json","husk_spawn_egg.json","ink_sac.json","iron_axe.json","iron_bars.json","iron_boots.json","iron_boots_amethyst_trim.json","iron_boots_copper_trim.json","iron_boots_diamond_trim.json","iron_boots_emerald_trim.json","iron_boots_gold_trim.json","iron_boots_iron_trim.json","iron_boots_lapis_trim.json","iron_boots_netherite_trim.json","iron_boots_quartz_trim.json","iron_boots_redstone_trim.json","iron_boots_resin_trim.json","iron_chestplate.json","iron_chestplate_amethyst_trim.json","iron_chestplate_copper_trim.json","iron_chestplate_diamond_trim.json","iron_chestplate_emerald_trim.json","iron_chestplate_gold_trim.json","iron_chestplate_iron_trim.json","iron_chestplate_lapis_trim.json","iron_chestplate_netherite_trim.json","iron_chestplate_quartz_trim.json","iron_chestplate_redstone_trim.json","iron_chestplate_resin_trim.json","iron_door.json","iron_golem_spawn_egg.json","iron_helmet.json","iron_helmet_amethyst_trim.json","iron_helmet_copper_trim.json","iron_helmet_diamond_trim.json","iron_helmet_emerald_trim.json","iron_helmet_gold_trim.json","iron_helmet_iron_trim.json","iron_helmet_lapis_trim.json","iron_helmet_netherite_trim.json","iron_helmet_quartz_trim.json","iron_helmet_redstone_trim.json","iron_helmet_resin_trim.json","iron_hoe.json","iron_horse_armor.json","iron_ingot.json","iron_leggings.json","iron_leggings_amethyst_trim.json","iron_leggings_copper_trim.json","iron_leggings_diamond_trim.json","iron_leggings_emerald_trim.json","iron_leggings_gold_trim.json","iron_leggings_iron_trim.json","iron_leggings_lapis_trim.json","iron_leggings_netherite_trim.json","iron_leggings_quartz_trim.json","iron_leggings_redstone_trim.json","iron_leggings_resin_trim.json","iron_nugget.json","iron_pickaxe.json","iron_shovel.json","iron_sword.json","item_frame.json","jungle_boat.json","jungle_chest_boat.json","jungle_door.json","jungle_hanging_sign.json","jungle_sapling.json","jungle_sign.json","kelp.json","knowledge_book.json","ladder.json","lantern.json","lapis_lazuli.json","large_amethyst_bud.json","large_fern.json","lava_bucket.json","lead.json","leaf_litter.json","leather.json","leather_boots.json","leather_boots_amethyst_trim.json","leather_boots_copper_trim.json","leather_boots_diamond_trim.json","leather_boots_emerald_trim.json","leather_boots_gold_trim.json","leather_boots_iron_trim.json","leather_boots_lapis_trim.json","leather_boots_netherite_trim.json","leather_boots_quartz_trim.json","leather_boots_redstone_trim.json","leather_boots_resin_trim.json","leather_chestplate.json","leather_chestplate_amethyst_trim.json","leather_chestplate_copper_trim.json","leather_chestplate_diamond_trim.json","leather_chestplate_emerald_trim.json","leather_chestplate_gold_trim.json","leather_chestplate_iron_trim.json","leather_chestplate_lapis_trim.json","leather_chestplate_netherite_trim.json","leather_chestplate_quartz_trim.json","leather_chestplate_redstone_trim.json","leather_chestplate_resin_trim.json","leather_helmet.json","leather_helmet_amethyst_trim.json","leather_helmet_copper_trim.json","leather_helmet_diamond_trim.json","leather_helmet_emerald_trim.json","leather_helmet_gold_trim.json","leather_helmet_iron_trim.json","leather_helmet_lapis_trim.json","leather_helmet_netherite_trim.json","leather_helmet_quartz_trim.json","leather_helmet_redstone_trim.json","leather_helmet_resin_trim.json","leather_horse_armor.json","leather_leggings.json","leather_leggings_amethyst_trim.json","leather_leggings_copper_trim.json","leather_leggings_diamond_trim.json","leather_leggings_emerald_trim.json","leather_leggings_gold_trim.json","leather_leggings_iron_trim.json","leather_leggings_lapis_trim.json","leather_leggings_netherite_trim.json","leather_leggings_quartz_trim.json","leather_leggings_redstone_trim.json","leather_leggings_resin_trim.json","lever.json","light.json","light_00.json","light_01.json","light_02.json","light_03.json","light_04.json","light_05.json","light_06.json","light_07.json","light_08.json","light_09.json","light_10.json","light_11.json","light_12.json","light_13.json","light_14.json","light_15.json","light_blue_bed.json","light_blue_bundle.json","light_blue_bundle_open_back.json","light_blue_bundle_open_front.json","light_blue_candle.json","light_blue_dye.json","light_blue_harness.json","light_blue_shulker_box.json","light_blue_stained_glass_pane.json","light_gray_bed.json","light_gray_bundle.json","light_gray_bundle_open_back.json","light_gray_bundle_open_front.json","light_gray_candle.json","light_gray_dye.json","light_gray_harness.json","light_gray_shulker_box.json","light_gray_stained_glass_pane.json","lilac.json","lily_of_the_valley.json","lily_pad.json","lime_bed.json","lime_bundle.json","lime_bundle_open_back.json","lime_bundle_open_front.json","lime_candle.json","lime_dye.json","lime_harness.json","lime_shulker_box.json","lime_stained_glass_pane.json","lingering_potion.json","llama_spawn_egg.json","mace.json","magenta_bed.json","magenta_bundle.json","magenta_bundle_open_back.json","magenta_bundle_open_front.json","magenta_candle.json","magenta_dye.json","magenta_harness.json","magenta_shulker_box.json","magenta_stained_glass_pane.json","magma_cream.json","magma_cube_spawn_egg.json","mangrove_boat.json","mangrove_chest_boat.json","mangrove_door.json","mangrove_hanging_sign.json","mangrove_propagule.json","mangrove_sign.json","map.json","medium_amethyst_bud.json","melon_seeds.json","melon_slice.json","milk_bucket.json","minecart.json","miner_pottery_sherd.json","mojang_banner_pattern.json","mooshroom_spawn_egg.json","mourner_pottery_sherd.json","mule_spawn_egg.json","mushroom_stew.json","music_disc_11.json","music_disc_13.json","music_disc_5.json","music_disc_blocks.json","music_disc_cat.json","music_disc_chirp.json","music_disc_creator.json","music_disc_creator_music_box.json","music_disc_far.json","music_disc_mall.json","music_disc_mellohi.json","music_disc_otherside.json","music_disc_pigstep.json","music_disc_precipice.json","music_disc_relic.json","music_disc_stal.json","music_disc_strad.json","music_disc_tears.json","music_disc_wait.json","music_disc_ward.json","mutton.json","name_tag.json","nautilus_shell.json","nether_brick.json","nether_sprouts.json","nether_star.json","nether_wart.json","netherite_axe.json","netherite_boots.json","netherite_boots_amethyst_trim.json","netherite_boots_copper_trim.json","netherite_boots_diamond_trim.json","netherite_boots_emerald_trim.json","netherite_boots_gold_trim.json","netherite_boots_iron_trim.json","netherite_boots_lapis_trim.json","netherite_boots_netherite_trim.json","netherite_boots_quartz_trim.json","netherite_boots_redstone_trim.json","netherite_boots_resin_trim.json","netherite_chestplate.json","netherite_chestplate_amethyst_trim.json","netherite_chestplate_copper_trim.json","netherite_chestplate_diamond_trim.json","netherite_chestplate_emerald_trim.json","netherite_chestplate_gold_trim.json","netherite_chestplate_iron_trim.json","netherite_chestplate_lapis_trim.json","netherite_chestplate_netherite_trim.json","netherite_chestplate_quartz_trim.json","netherite_chestplate_redstone_trim.json","netherite_chestplate_resin_trim.json","netherite_helmet.json","netherite_helmet_amethyst_trim.json","netherite_helmet_copper_trim.json","netherite_helmet_diamond_trim.json","netherite_helmet_emerald_trim.json","netherite_helmet_gold_trim.json","netherite_helmet_iron_trim.json","netherite_helmet_lapis_trim.json","netherite_helmet_netherite_trim.json","netherite_helmet_quartz_trim.json","netherite_helmet_redstone_trim.json","netherite_helmet_resin_trim.json","netherite_hoe.json","netherite_ingot.json","netherite_leggings.json","netherite_leggings_amethyst_trim.json","netherite_leggings_copper_trim.json","netherite_leggings_diamond_trim.json","netherite_leggings_emerald_trim.json","netherite_leggings_gold_trim.json","netherite_leggings_iron_trim.json","netherite_leggings_lapis_trim.json","netherite_leggings_netherite_trim.json","netherite_leggings_quartz_trim.json","netherite_leggings_redstone_trim.json","netherite_leggings_resin_trim.json","netherite_pickaxe.json","netherite_scrap.json","netherite_shovel.json","netherite_sword.json","netherite_upgrade_smithing_template.json","oak_boat.json","oak_chest_boat.json","oak_door.json","oak_hanging_sign.json","oak_sapling.json","oak_sign.json","ocelot_spawn_egg.json","ominous_bottle.json","ominous_trial_key.json","open_eyeblossom.json","orange_bed.json","orange_bundle.json","orange_bundle_open_back.json","orange_bundle_open_front.json","orange_candle.json","orange_dye.json","orange_harness.json","orange_shulker_box.json","orange_stained_glass_pane.json","orange_tulip.json","oxeye_daisy.json","oxidized_copper_door.json","painting.json","pale_hanging_moss.json","pale_oak_boat.json","pale_oak_chest_boat.json","pale_oak_door.json","pale_oak_hanging_sign.json","pale_oak_sapling.json","pale_oak_sign.json","panda_spawn_egg.json","paper.json","parrot_spawn_egg.json","peony.json","phantom_membrane.json","phantom_spawn_egg.json","pig_spawn_egg.json","piglin_banner_pattern.json","piglin_brute_spawn_egg.json","piglin_spawn_egg.json","pillager_spawn_egg.json","pink_bed.json","pink_bundle.json","pink_bundle_open_back.json","pink_bundle_open_front.json","pink_candle.json","pink_dye.json","pink_harness.json","pink_petals.json","pink_shulker_box.json","pink_stained_glass_pane.json","pink_tulip.json","pitcher_plant.json","pitcher_pod.json","plenty_pottery_sherd.json","pointed_dripstone.json","poisonous_potato.json","polar_bear_spawn_egg.json","popped_chorus_fruit.json","poppy.json","porkchop.json","potato.json","potion.json","powder_snow_bucket.json","powered_rail.json","prismarine_crystals.json","prismarine_shard.json","prize_pottery_sherd.json","pufferfish.json","pufferfish_bucket.json","pufferfish_spawn_egg.json","pumpkin_pie.json","pumpkin_seeds.json","purple_bed.json","purple_bundle.json","purple_bundle_open_back.json","purple_bundle_open_front.json","purple_candle.json","purple_dye.json","purple_harness.json","purple_shulker_box.json","purple_stained_glass_pane.json","quartz.json","rabbit.json","rabbit_foot.json","rabbit_hide.json","rabbit_spawn_egg.json","rabbit_stew.json","rail.json","raiser_armor_trim_smithing_template.json","ravager_spawn_egg.json","raw_copper.json","raw_gold.json","raw_iron.json","recovery_compass_00.json","recovery_compass_01.json","recovery_compass_02.json","recovery_compass_03.json","recovery_compass_04.json","recovery_compass_05.json","recovery_compass_06.json","recovery_compass_07.json","recovery_compass_08.json","recovery_compass_09.json","recovery_compass_10.json","recovery_compass_11.json","recovery_compass_12.json","recovery_compass_13.json","recovery_compass_14.json","recovery_compass_15.json","recovery_compass_16.json","recovery_compass_17.json","recovery_compass_18.json","recovery_compass_19.json","recovery_compass_20.json","recovery_compass_21.json","recovery_compass_22.json","recovery_compass_23.json","recovery_compass_24.json","recovery_compass_25.json","recovery_compass_26.json","recovery_compass_27.json","recovery_compass_28.json","recovery_compass_29.json","recovery_compass_30.json","recovery_compass_31.json","red_bed.json","red_bundle.json","red_bundle_open_back.json","red_bundle_open_front.json","red_candle.json","red_dye.json","red_harness.json","red_mushroom.json","red_shulker_box.json","red_stained_glass_pane.json","red_tulip.json","redstone.json","redstone_torch.json","repeater.json","resin_brick.json","resin_clump.json","rib_armor_trim_smithing_template.json","rose_bush.json","rotten_flesh.json","saddle.json","salmon.json","salmon_bucket.json","salmon_spawn_egg.json","scrape_pottery_sherd.json","sculk_vein.json","sea_pickle.json","seagrass.json","sentry_armor_trim_smithing_template.json","shaper_armor_trim_smithing_template.json","sheaf_pottery_sherd.json","shears.json","sheep_spawn_egg.json","shelter_pottery_sherd.json","shield.json","shield_blocking.json","short_dry_grass.json","short_grass.json","shulker_box.json","shulker_shell.json","shulker_spawn_egg.json","silence_armor_trim_smithing_template.json","silverfish_spawn_egg.json","skeleton_horse_spawn_egg.json","skeleton_spawn_egg.json","skull_banner_pattern.json","skull_pottery_sherd.json","slime_ball.json","slime_spawn_egg.json","small_amethyst_bud.json","small_dripleaf.json","sniffer_egg.json","sniffer_spawn_egg.json","snort_pottery_sherd.json","snout_armor_trim_smithing_template.json","snow_golem_spawn_egg.json","snowball.json","soul_campfire.json","soul_lantern.json","soul_torch.json","spectral_arrow.json","spider_eye.json","spider_spawn_egg.json","spire_armor_trim_smithing_template.json","splash_potion.json","spruce_boat.json","spruce_chest_boat.json","spruce_door.json","spruce_hanging_sign.json","spruce_sapling.json","spruce_sign.json","spyglass.json","spyglass_in_hand.json","squid_spawn_egg.json","stick.json","stone_axe.json","stone_hoe.json","stone_pickaxe.json","stone_shovel.json","stone_sword.json","stray_spawn_egg.json","strider_spawn_egg.json","string.json","structure_void.json","sugar.json","sugar_cane.json","sunflower.json","suspicious_stew.json","sweet_berries.json","tadpole_bucket.json","tadpole_spawn_egg.json","tall_dry_grass.json","tall_grass.json","template_banner.json","template_bed.json","template_bundle_open_back.json","template_bundle_open_front.json","template_chest.json","template_music_disc.json","template_shulker_box.json","template_skull.json","tide_armor_trim_smithing_template.json","tipped_arrow.json","tnt_minecart.json","tooting_goat_horn.json","torch.json","torchflower.json","torchflower_seeds.json","totem_of_undying.json","trader_llama_spawn_egg.json","trapped_chest.json","trial_key.json","trident.json","trident_in_hand.json","trident_throwing.json","tripwire_hook.json","tropical_fish.json","tropical_fish_bucket.json","tropical_fish_spawn_egg.json","tube_coral.json","tube_coral_fan.json","turtle_egg.json","turtle_helmet.json","turtle_helmet_amethyst_trim.json","turtle_helmet_copper_trim.json","turtle_helmet_diamond_trim.json","turtle_helmet_emerald_trim.json","turtle_helmet_gold_trim.json","turtle_helmet_iron_trim.json","turtle_helmet_lapis_trim.json","turtle_helmet_netherite_trim.json","turtle_helmet_quartz_trim.json","turtle_helmet_redstone_trim.json","turtle_helmet_resin_trim.json","turtle_scute.json","turtle_spawn_egg.json","twisting_vines.json","vex_armor_trim_smithing_template.json","vex_spawn_egg.json","villager_spawn_egg.json","vindicator_spawn_egg.json","vine.json","wandering_trader_spawn_egg.json","ward_armor_trim_smithing_template.json","warden_spawn_egg.json","warped_door.json","warped_fungus.json","warped_fungus_on_a_stick.json","warped_hanging_sign.json","warped_roots.json","warped_sign.json","water_bucket.json","wayfinder_armor_trim_smithing_template.json","weathered_copper_door.json","weeping_vines.json","wheat.json","wheat_seeds.json","white_bed.json","white_bundle.json","white_bundle_open_back.json","white_bundle_open_front.json","white_candle.json","white_dye.json","white_harness.json","white_shulker_box.json","white_stained_glass_pane.json","white_tulip.json","wild_armor_trim_smithing_template.json","wildflowers.json","wind_charge.json","witch_spawn_egg.json","wither_rose.json","wither_skeleton_spawn_egg.json","wither_spawn_egg.json","wolf_armor.json","wolf_armor_dyed.json","wolf_spawn_egg.json","wooden_axe.json","wooden_hoe.json","wooden_pickaxe.json","wooden_shovel.json","wooden_sword.json","writable_book.json","written_book.json","yellow_bed.json","yellow_bundle.json","yellow_bundle_open_back.json","yellow_bundle_open_front.json","yellow_candle.json","yellow_dye.json","yellow_harness.json","yellow_shulker_box.json","yellow_stained_glass_pane.json","zoglin_spawn_egg.json","zombie_horse_spawn_egg.json","zombie_spawn_egg.json","zombie_villager_spawn_egg.json","zombified_piglin_spawn_egg.json"]} \ No newline at end of file +{"directories":[],"files":["acacia_boat.json","acacia_chest_boat.json","acacia_door.json","acacia_hanging_sign.json","acacia_sapling.json","acacia_sign.json","activator_rail.json","air.json","allay_spawn_egg.json","allium.json","amethyst_bud.json","amethyst_cluster.json","amethyst_shard.json","angler_pottery_sherd.json","apple.json","archer_pottery_sherd.json","armadillo_scute.json","armadillo_spawn_egg.json","armor_stand.json","arms_up_pottery_sherd.json","arrow.json","axolotl_bucket.json","axolotl_spawn_egg.json","azure_bluet.json","baked_potato.json","bamboo.json","bamboo_chest_raft.json","bamboo_door.json","bamboo_hanging_sign.json","bamboo_raft.json","bamboo_sign.json","barrier.json","bat_spawn_egg.json","bee_spawn_egg.json","beef.json","beetroot.json","beetroot_seeds.json","beetroot_soup.json","bell.json","big_dripleaf.json","birch_boat.json","birch_chest_boat.json","birch_door.json","birch_hanging_sign.json","birch_sapling.json","birch_sign.json","black_bed.json","black_bundle.json","black_bundle_open_back.json","black_bundle_open_front.json","black_candle.json","black_dye.json","black_harness.json","black_shulker_box.json","black_stained_glass_pane.json","blade_pottery_sherd.json","blaze_powder.json","blaze_rod.json","blaze_spawn_egg.json","blue_bed.json","blue_bundle.json","blue_bundle_open_back.json","blue_bundle_open_front.json","blue_candle.json","blue_dye.json","blue_egg.json","blue_harness.json","blue_orchid.json","blue_shulker_box.json","blue_stained_glass_pane.json","bogged_spawn_egg.json","bolt_armor_trim_smithing_template.json","bone.json","bone_meal.json","book.json","bordure_indented_banner_pattern.json","bow.json","bow_pulling_0.json","bow_pulling_1.json","bow_pulling_2.json","bowl.json","brain_coral.json","brain_coral_fan.json","bread.json","breeze_rod.json","breeze_spawn_egg.json","brewer_pottery_sherd.json","brewing_stand.json","brick.json","brown_bed.json","brown_bundle.json","brown_bundle_open_back.json","brown_bundle_open_front.json","brown_candle.json","brown_dye.json","brown_egg.json","brown_harness.json","brown_mushroom.json","brown_shulker_box.json","brown_stained_glass_pane.json","brush.json","brush_brushing_0.json","brush_brushing_1.json","brush_brushing_2.json","bubble_coral.json","bubble_coral_fan.json","bucket.json","bundle.json","bundle_open_back.json","bundle_open_front.json","burn_pottery_sherd.json","bush.json","cactus_flower.json","cake.json","camel_spawn_egg.json","campfire.json","candle.json","carrot.json","carrot_on_a_stick.json","cat_spawn_egg.json","cauldron.json","cave_spider_spawn_egg.json","chain.json","chainmail_boots.json","chainmail_boots_amethyst_trim.json","chainmail_boots_copper_trim.json","chainmail_boots_diamond_trim.json","chainmail_boots_emerald_trim.json","chainmail_boots_gold_trim.json","chainmail_boots_iron_trim.json","chainmail_boots_lapis_trim.json","chainmail_boots_netherite_trim.json","chainmail_boots_quartz_trim.json","chainmail_boots_redstone_trim.json","chainmail_boots_resin_trim.json","chainmail_chestplate.json","chainmail_chestplate_amethyst_trim.json","chainmail_chestplate_copper_trim.json","chainmail_chestplate_diamond_trim.json","chainmail_chestplate_emerald_trim.json","chainmail_chestplate_gold_trim.json","chainmail_chestplate_iron_trim.json","chainmail_chestplate_lapis_trim.json","chainmail_chestplate_netherite_trim.json","chainmail_chestplate_quartz_trim.json","chainmail_chestplate_redstone_trim.json","chainmail_chestplate_resin_trim.json","chainmail_helmet.json","chainmail_helmet_amethyst_trim.json","chainmail_helmet_copper_trim.json","chainmail_helmet_diamond_trim.json","chainmail_helmet_emerald_trim.json","chainmail_helmet_gold_trim.json","chainmail_helmet_iron_trim.json","chainmail_helmet_lapis_trim.json","chainmail_helmet_netherite_trim.json","chainmail_helmet_quartz_trim.json","chainmail_helmet_redstone_trim.json","chainmail_helmet_resin_trim.json","chainmail_leggings.json","chainmail_leggings_amethyst_trim.json","chainmail_leggings_copper_trim.json","chainmail_leggings_diamond_trim.json","chainmail_leggings_emerald_trim.json","chainmail_leggings_gold_trim.json","chainmail_leggings_iron_trim.json","chainmail_leggings_lapis_trim.json","chainmail_leggings_netherite_trim.json","chainmail_leggings_quartz_trim.json","chainmail_leggings_redstone_trim.json","chainmail_leggings_resin_trim.json","charcoal.json","cherry_boat.json","cherry_chest_boat.json","cherry_door.json","cherry_hanging_sign.json","cherry_sapling.json","cherry_sign.json","chest.json","chest_minecart.json","chicken.json","chicken_spawn_egg.json","chorus_fruit.json","clay_ball.json","clock_00.json","clock_01.json","clock_02.json","clock_03.json","clock_04.json","clock_05.json","clock_06.json","clock_07.json","clock_08.json","clock_09.json","clock_10.json","clock_11.json","clock_12.json","clock_13.json","clock_14.json","clock_15.json","clock_16.json","clock_17.json","clock_18.json","clock_19.json","clock_20.json","clock_21.json","clock_22.json","clock_23.json","clock_24.json","clock_25.json","clock_26.json","clock_27.json","clock_28.json","clock_29.json","clock_30.json","clock_31.json","clock_32.json","clock_33.json","clock_34.json","clock_35.json","clock_36.json","clock_37.json","clock_38.json","clock_39.json","clock_40.json","clock_41.json","clock_42.json","clock_43.json","clock_44.json","clock_45.json","clock_46.json","clock_47.json","clock_48.json","clock_49.json","clock_50.json","clock_51.json","clock_52.json","clock_53.json","clock_54.json","clock_55.json","clock_56.json","clock_57.json","clock_58.json","clock_59.json","clock_60.json","clock_61.json","clock_62.json","clock_63.json","closed_eyeblossom.json","coal.json","coast_armor_trim_smithing_template.json","cobweb.json","cocoa_beans.json","cod.json","cod_bucket.json","cod_spawn_egg.json","command_block_minecart.json","comparator.json","compass_00.json","compass_01.json","compass_02.json","compass_03.json","compass_04.json","compass_05.json","compass_06.json","compass_07.json","compass_08.json","compass_09.json","compass_10.json","compass_11.json","compass_12.json","compass_13.json","compass_14.json","compass_15.json","compass_16.json","compass_17.json","compass_18.json","compass_19.json","compass_20.json","compass_21.json","compass_22.json","compass_23.json","compass_24.json","compass_25.json","compass_26.json","compass_27.json","compass_28.json","compass_29.json","compass_30.json","compass_31.json","conduit.json","cooked_beef.json","cooked_chicken.json","cooked_cod.json","cooked_mutton.json","cooked_porkchop.json","cooked_rabbit.json","cooked_salmon.json","cookie.json","copper_door.json","copper_ingot.json","cornflower.json","cow_spawn_egg.json","creaking_spawn_egg.json","creeper_banner_pattern.json","creeper_spawn_egg.json","crimson_door.json","crimson_fungus.json","crimson_hanging_sign.json","crimson_roots.json","crimson_sign.json","crossbow.json","crossbow_arrow.json","crossbow_firework.json","crossbow_pulling_0.json","crossbow_pulling_1.json","crossbow_pulling_2.json","cyan_bed.json","cyan_bundle.json","cyan_bundle_open_back.json","cyan_bundle_open_front.json","cyan_candle.json","cyan_dye.json","cyan_harness.json","cyan_shulker_box.json","cyan_stained_glass_pane.json","dandelion.json","danger_pottery_sherd.json","dark_oak_boat.json","dark_oak_chest_boat.json","dark_oak_door.json","dark_oak_hanging_sign.json","dark_oak_sapling.json","dark_oak_sign.json","dead_brain_coral.json","dead_brain_coral_fan.json","dead_bubble_coral.json","dead_bubble_coral_fan.json","dead_bush.json","dead_fire_coral.json","dead_fire_coral_fan.json","dead_horn_coral.json","dead_horn_coral_fan.json","dead_tube_coral.json","dead_tube_coral_fan.json","debug_stick.json","decorated_pot.json","detector_rail.json","diamond.json","diamond_axe.json","diamond_boots.json","diamond_boots_amethyst_trim.json","diamond_boots_copper_trim.json","diamond_boots_diamond_trim.json","diamond_boots_emerald_trim.json","diamond_boots_gold_trim.json","diamond_boots_iron_trim.json","diamond_boots_lapis_trim.json","diamond_boots_netherite_trim.json","diamond_boots_quartz_trim.json","diamond_boots_redstone_trim.json","diamond_boots_resin_trim.json","diamond_chestplate.json","diamond_chestplate_amethyst_trim.json","diamond_chestplate_copper_trim.json","diamond_chestplate_diamond_trim.json","diamond_chestplate_emerald_trim.json","diamond_chestplate_gold_trim.json","diamond_chestplate_iron_trim.json","diamond_chestplate_lapis_trim.json","diamond_chestplate_netherite_trim.json","diamond_chestplate_quartz_trim.json","diamond_chestplate_redstone_trim.json","diamond_chestplate_resin_trim.json","diamond_helmet.json","diamond_helmet_amethyst_trim.json","diamond_helmet_copper_trim.json","diamond_helmet_diamond_trim.json","diamond_helmet_emerald_trim.json","diamond_helmet_gold_trim.json","diamond_helmet_iron_trim.json","diamond_helmet_lapis_trim.json","diamond_helmet_netherite_trim.json","diamond_helmet_quartz_trim.json","diamond_helmet_redstone_trim.json","diamond_helmet_resin_trim.json","diamond_hoe.json","diamond_horse_armor.json","diamond_leggings.json","diamond_leggings_amethyst_trim.json","diamond_leggings_copper_trim.json","diamond_leggings_diamond_trim.json","diamond_leggings_emerald_trim.json","diamond_leggings_gold_trim.json","diamond_leggings_iron_trim.json","diamond_leggings_lapis_trim.json","diamond_leggings_netherite_trim.json","diamond_leggings_quartz_trim.json","diamond_leggings_redstone_trim.json","diamond_leggings_resin_trim.json","diamond_pickaxe.json","diamond_shovel.json","diamond_sword.json","disc_fragment_5.json","dolphin_spawn_egg.json","donkey_spawn_egg.json","dragon_breath.json","dragon_head.json","dried_kelp.json","drowned_spawn_egg.json","dune_armor_trim_smithing_template.json","echo_shard.json","egg.json","elder_guardian_spawn_egg.json","elytra.json","elytra_broken.json","emerald.json","enchanted_book.json","enchanted_golden_apple.json","end_crystal.json","ender_chest.json","ender_dragon_spawn_egg.json","ender_eye.json","ender_pearl.json","enderman_spawn_egg.json","endermite_spawn_egg.json","evoker_spawn_egg.json","experience_bottle.json","explorer_pottery_sherd.json","exposed_copper_door.json","eye_armor_trim_smithing_template.json","feather.json","fermented_spider_eye.json","fern.json","field_masoned_banner_pattern.json","filled_map.json","fire_charge.json","fire_coral.json","fire_coral_fan.json","firefly_bush.json","firework_rocket.json","firework_star.json","fishing_rod.json","fishing_rod_cast.json","flint.json","flint_and_steel.json","flow_armor_trim_smithing_template.json","flow_banner_pattern.json","flow_pottery_sherd.json","flower_banner_pattern.json","flower_pot.json","fox_spawn_egg.json","friend_pottery_sherd.json","frog_spawn_egg.json","frogspawn.json","furnace_minecart.json","generated.json","ghast_spawn_egg.json","ghast_tear.json","glass_bottle.json","glass_pane.json","glistering_melon_slice.json","globe_banner_pattern.json","glow_berries.json","glow_ink_sac.json","glow_item_frame.json","glow_lichen.json","glow_squid_spawn_egg.json","glowstone_dust.json","goat_horn.json","goat_spawn_egg.json","gold_ingot.json","gold_nugget.json","golden_apple.json","golden_axe.json","golden_boots.json","golden_boots_amethyst_trim.json","golden_boots_copper_trim.json","golden_boots_diamond_trim.json","golden_boots_emerald_trim.json","golden_boots_gold_trim.json","golden_boots_iron_trim.json","golden_boots_lapis_trim.json","golden_boots_netherite_trim.json","golden_boots_quartz_trim.json","golden_boots_redstone_trim.json","golden_boots_resin_trim.json","golden_carrot.json","golden_chestplate.json","golden_chestplate_amethyst_trim.json","golden_chestplate_copper_trim.json","golden_chestplate_diamond_trim.json","golden_chestplate_emerald_trim.json","golden_chestplate_gold_trim.json","golden_chestplate_iron_trim.json","golden_chestplate_lapis_trim.json","golden_chestplate_netherite_trim.json","golden_chestplate_quartz_trim.json","golden_chestplate_redstone_trim.json","golden_chestplate_resin_trim.json","golden_helmet.json","golden_helmet_amethyst_trim.json","golden_helmet_copper_trim.json","golden_helmet_diamond_trim.json","golden_helmet_emerald_trim.json","golden_helmet_gold_trim.json","golden_helmet_iron_trim.json","golden_helmet_lapis_trim.json","golden_helmet_netherite_trim.json","golden_helmet_quartz_trim.json","golden_helmet_redstone_trim.json","golden_helmet_resin_trim.json","golden_hoe.json","golden_horse_armor.json","golden_leggings.json","golden_leggings_amethyst_trim.json","golden_leggings_copper_trim.json","golden_leggings_diamond_trim.json","golden_leggings_emerald_trim.json","golden_leggings_gold_trim.json","golden_leggings_iron_trim.json","golden_leggings_lapis_trim.json","golden_leggings_netherite_trim.json","golden_leggings_quartz_trim.json","golden_leggings_redstone_trim.json","golden_leggings_resin_trim.json","golden_pickaxe.json","golden_shovel.json","golden_sword.json","gray_bed.json","gray_bundle.json","gray_bundle_open_back.json","gray_bundle_open_front.json","gray_candle.json","gray_dye.json","gray_harness.json","gray_shulker_box.json","gray_stained_glass_pane.json","green_bed.json","green_bundle.json","green_bundle_open_back.json","green_bundle_open_front.json","green_candle.json","green_dye.json","green_harness.json","green_shulker_box.json","green_stained_glass_pane.json","guardian_spawn_egg.json","gunpowder.json","guster_banner_pattern.json","guster_pottery_sherd.json","handheld.json","handheld_mace.json","handheld_rod.json","hanging_roots.json","happy_ghast_spawn_egg.json","heart_of_the_sea.json","heart_pottery_sherd.json","heartbreak_pottery_sherd.json","hoglin_spawn_egg.json","honey_bottle.json","honeycomb.json","hopper.json","hopper_minecart.json","horn_coral.json","horn_coral_fan.json","horse_spawn_egg.json","host_armor_trim_smithing_template.json","howl_pottery_sherd.json","husk_spawn_egg.json","ink_sac.json","iron_axe.json","iron_bars.json","iron_boots.json","iron_boots_amethyst_trim.json","iron_boots_copper_trim.json","iron_boots_diamond_trim.json","iron_boots_emerald_trim.json","iron_boots_gold_trim.json","iron_boots_iron_trim.json","iron_boots_lapis_trim.json","iron_boots_netherite_trim.json","iron_boots_quartz_trim.json","iron_boots_redstone_trim.json","iron_boots_resin_trim.json","iron_chestplate.json","iron_chestplate_amethyst_trim.json","iron_chestplate_copper_trim.json","iron_chestplate_diamond_trim.json","iron_chestplate_emerald_trim.json","iron_chestplate_gold_trim.json","iron_chestplate_iron_trim.json","iron_chestplate_lapis_trim.json","iron_chestplate_netherite_trim.json","iron_chestplate_quartz_trim.json","iron_chestplate_redstone_trim.json","iron_chestplate_resin_trim.json","iron_door.json","iron_golem_spawn_egg.json","iron_helmet.json","iron_helmet_amethyst_trim.json","iron_helmet_copper_trim.json","iron_helmet_diamond_trim.json","iron_helmet_emerald_trim.json","iron_helmet_gold_trim.json","iron_helmet_iron_trim.json","iron_helmet_lapis_trim.json","iron_helmet_netherite_trim.json","iron_helmet_quartz_trim.json","iron_helmet_redstone_trim.json","iron_helmet_resin_trim.json","iron_hoe.json","iron_horse_armor.json","iron_ingot.json","iron_leggings.json","iron_leggings_amethyst_trim.json","iron_leggings_copper_trim.json","iron_leggings_diamond_trim.json","iron_leggings_emerald_trim.json","iron_leggings_gold_trim.json","iron_leggings_iron_trim.json","iron_leggings_lapis_trim.json","iron_leggings_netherite_trim.json","iron_leggings_quartz_trim.json","iron_leggings_redstone_trim.json","iron_leggings_resin_trim.json","iron_nugget.json","iron_pickaxe.json","iron_shovel.json","iron_sword.json","item_frame.json","jungle_boat.json","jungle_chest_boat.json","jungle_door.json","jungle_hanging_sign.json","jungle_sapling.json","jungle_sign.json","kelp.json","knowledge_book.json","ladder.json","lantern.json","lapis_lazuli.json","large_amethyst_bud.json","large_fern.json","lava_bucket.json","lead.json","leaf_litter.json","leather.json","leather_boots.json","leather_boots_amethyst_trim.json","leather_boots_copper_trim.json","leather_boots_diamond_trim.json","leather_boots_emerald_trim.json","leather_boots_gold_trim.json","leather_boots_iron_trim.json","leather_boots_lapis_trim.json","leather_boots_netherite_trim.json","leather_boots_quartz_trim.json","leather_boots_redstone_trim.json","leather_boots_resin_trim.json","leather_chestplate.json","leather_chestplate_amethyst_trim.json","leather_chestplate_copper_trim.json","leather_chestplate_diamond_trim.json","leather_chestplate_emerald_trim.json","leather_chestplate_gold_trim.json","leather_chestplate_iron_trim.json","leather_chestplate_lapis_trim.json","leather_chestplate_netherite_trim.json","leather_chestplate_quartz_trim.json","leather_chestplate_redstone_trim.json","leather_chestplate_resin_trim.json","leather_helmet.json","leather_helmet_amethyst_trim.json","leather_helmet_copper_trim.json","leather_helmet_diamond_trim.json","leather_helmet_emerald_trim.json","leather_helmet_gold_trim.json","leather_helmet_iron_trim.json","leather_helmet_lapis_trim.json","leather_helmet_netherite_trim.json","leather_helmet_quartz_trim.json","leather_helmet_redstone_trim.json","leather_helmet_resin_trim.json","leather_horse_armor.json","leather_leggings.json","leather_leggings_amethyst_trim.json","leather_leggings_copper_trim.json","leather_leggings_diamond_trim.json","leather_leggings_emerald_trim.json","leather_leggings_gold_trim.json","leather_leggings_iron_trim.json","leather_leggings_lapis_trim.json","leather_leggings_netherite_trim.json","leather_leggings_quartz_trim.json","leather_leggings_redstone_trim.json","leather_leggings_resin_trim.json","lever.json","light.json","light_00.json","light_01.json","light_02.json","light_03.json","light_04.json","light_05.json","light_06.json","light_07.json","light_08.json","light_09.json","light_10.json","light_11.json","light_12.json","light_13.json","light_14.json","light_15.json","light_blue_bed.json","light_blue_bundle.json","light_blue_bundle_open_back.json","light_blue_bundle_open_front.json","light_blue_candle.json","light_blue_dye.json","light_blue_harness.json","light_blue_shulker_box.json","light_blue_stained_glass_pane.json","light_gray_bed.json","light_gray_bundle.json","light_gray_bundle_open_back.json","light_gray_bundle_open_front.json","light_gray_candle.json","light_gray_dye.json","light_gray_harness.json","light_gray_shulker_box.json","light_gray_stained_glass_pane.json","lilac.json","lily_of_the_valley.json","lily_pad.json","lime_bed.json","lime_bundle.json","lime_bundle_open_back.json","lime_bundle_open_front.json","lime_candle.json","lime_dye.json","lime_harness.json","lime_shulker_box.json","lime_stained_glass_pane.json","lingering_potion.json","llama_spawn_egg.json","mace.json","magenta_bed.json","magenta_bundle.json","magenta_bundle_open_back.json","magenta_bundle_open_front.json","magenta_candle.json","magenta_dye.json","magenta_harness.json","magenta_shulker_box.json","magenta_stained_glass_pane.json","magma_cream.json","magma_cube_spawn_egg.json","mangrove_boat.json","mangrove_chest_boat.json","mangrove_door.json","mangrove_hanging_sign.json","mangrove_propagule.json","mangrove_sign.json","map.json","medium_amethyst_bud.json","melon_seeds.json","melon_slice.json","milk_bucket.json","minecart.json","miner_pottery_sherd.json","mojang_banner_pattern.json","mooshroom_spawn_egg.json","mourner_pottery_sherd.json","mule_spawn_egg.json","mushroom_stew.json","music_disc_11.json","music_disc_13.json","music_disc_5.json","music_disc_blocks.json","music_disc_cat.json","music_disc_chirp.json","music_disc_creator.json","music_disc_creator_music_box.json","music_disc_far.json","music_disc_lava_chicken.json","music_disc_mall.json","music_disc_mellohi.json","music_disc_otherside.json","music_disc_pigstep.json","music_disc_precipice.json","music_disc_relic.json","music_disc_stal.json","music_disc_strad.json","music_disc_tears.json","music_disc_wait.json","music_disc_ward.json","mutton.json","name_tag.json","nautilus_shell.json","nether_brick.json","nether_sprouts.json","nether_star.json","nether_wart.json","netherite_axe.json","netherite_boots.json","netherite_boots_amethyst_trim.json","netherite_boots_copper_trim.json","netherite_boots_diamond_trim.json","netherite_boots_emerald_trim.json","netherite_boots_gold_trim.json","netherite_boots_iron_trim.json","netherite_boots_lapis_trim.json","netherite_boots_netherite_trim.json","netherite_boots_quartz_trim.json","netherite_boots_redstone_trim.json","netherite_boots_resin_trim.json","netherite_chestplate.json","netherite_chestplate_amethyst_trim.json","netherite_chestplate_copper_trim.json","netherite_chestplate_diamond_trim.json","netherite_chestplate_emerald_trim.json","netherite_chestplate_gold_trim.json","netherite_chestplate_iron_trim.json","netherite_chestplate_lapis_trim.json","netherite_chestplate_netherite_trim.json","netherite_chestplate_quartz_trim.json","netherite_chestplate_redstone_trim.json","netherite_chestplate_resin_trim.json","netherite_helmet.json","netherite_helmet_amethyst_trim.json","netherite_helmet_copper_trim.json","netherite_helmet_diamond_trim.json","netherite_helmet_emerald_trim.json","netherite_helmet_gold_trim.json","netherite_helmet_iron_trim.json","netherite_helmet_lapis_trim.json","netherite_helmet_netherite_trim.json","netherite_helmet_quartz_trim.json","netherite_helmet_redstone_trim.json","netherite_helmet_resin_trim.json","netherite_hoe.json","netherite_ingot.json","netherite_leggings.json","netherite_leggings_amethyst_trim.json","netherite_leggings_copper_trim.json","netherite_leggings_diamond_trim.json","netherite_leggings_emerald_trim.json","netherite_leggings_gold_trim.json","netherite_leggings_iron_trim.json","netherite_leggings_lapis_trim.json","netherite_leggings_netherite_trim.json","netherite_leggings_quartz_trim.json","netherite_leggings_redstone_trim.json","netherite_leggings_resin_trim.json","netherite_pickaxe.json","netherite_scrap.json","netherite_shovel.json","netherite_sword.json","netherite_upgrade_smithing_template.json","oak_boat.json","oak_chest_boat.json","oak_door.json","oak_hanging_sign.json","oak_sapling.json","oak_sign.json","ocelot_spawn_egg.json","ominous_bottle.json","ominous_trial_key.json","open_eyeblossom.json","orange_bed.json","orange_bundle.json","orange_bundle_open_back.json","orange_bundle_open_front.json","orange_candle.json","orange_dye.json","orange_harness.json","orange_shulker_box.json","orange_stained_glass_pane.json","orange_tulip.json","oxeye_daisy.json","oxidized_copper_door.json","painting.json","pale_hanging_moss.json","pale_oak_boat.json","pale_oak_chest_boat.json","pale_oak_door.json","pale_oak_hanging_sign.json","pale_oak_sapling.json","pale_oak_sign.json","panda_spawn_egg.json","paper.json","parrot_spawn_egg.json","peony.json","phantom_membrane.json","phantom_spawn_egg.json","pig_spawn_egg.json","piglin_banner_pattern.json","piglin_brute_spawn_egg.json","piglin_spawn_egg.json","pillager_spawn_egg.json","pink_bed.json","pink_bundle.json","pink_bundle_open_back.json","pink_bundle_open_front.json","pink_candle.json","pink_dye.json","pink_harness.json","pink_petals.json","pink_shulker_box.json","pink_stained_glass_pane.json","pink_tulip.json","pitcher_plant.json","pitcher_pod.json","plenty_pottery_sherd.json","pointed_dripstone.json","poisonous_potato.json","polar_bear_spawn_egg.json","popped_chorus_fruit.json","poppy.json","porkchop.json","potato.json","potion.json","powder_snow_bucket.json","powered_rail.json","prismarine_crystals.json","prismarine_shard.json","prize_pottery_sherd.json","pufferfish.json","pufferfish_bucket.json","pufferfish_spawn_egg.json","pumpkin_pie.json","pumpkin_seeds.json","purple_bed.json","purple_bundle.json","purple_bundle_open_back.json","purple_bundle_open_front.json","purple_candle.json","purple_dye.json","purple_harness.json","purple_shulker_box.json","purple_stained_glass_pane.json","quartz.json","rabbit.json","rabbit_foot.json","rabbit_hide.json","rabbit_spawn_egg.json","rabbit_stew.json","rail.json","raiser_armor_trim_smithing_template.json","ravager_spawn_egg.json","raw_copper.json","raw_gold.json","raw_iron.json","recovery_compass_00.json","recovery_compass_01.json","recovery_compass_02.json","recovery_compass_03.json","recovery_compass_04.json","recovery_compass_05.json","recovery_compass_06.json","recovery_compass_07.json","recovery_compass_08.json","recovery_compass_09.json","recovery_compass_10.json","recovery_compass_11.json","recovery_compass_12.json","recovery_compass_13.json","recovery_compass_14.json","recovery_compass_15.json","recovery_compass_16.json","recovery_compass_17.json","recovery_compass_18.json","recovery_compass_19.json","recovery_compass_20.json","recovery_compass_21.json","recovery_compass_22.json","recovery_compass_23.json","recovery_compass_24.json","recovery_compass_25.json","recovery_compass_26.json","recovery_compass_27.json","recovery_compass_28.json","recovery_compass_29.json","recovery_compass_30.json","recovery_compass_31.json","red_bed.json","red_bundle.json","red_bundle_open_back.json","red_bundle_open_front.json","red_candle.json","red_dye.json","red_harness.json","red_mushroom.json","red_shulker_box.json","red_stained_glass_pane.json","red_tulip.json","redstone.json","redstone_torch.json","repeater.json","resin_brick.json","resin_clump.json","rib_armor_trim_smithing_template.json","rose_bush.json","rotten_flesh.json","saddle.json","salmon.json","salmon_bucket.json","salmon_spawn_egg.json","scrape_pottery_sherd.json","sculk_vein.json","sea_pickle.json","seagrass.json","sentry_armor_trim_smithing_template.json","shaper_armor_trim_smithing_template.json","sheaf_pottery_sherd.json","shears.json","sheep_spawn_egg.json","shelter_pottery_sherd.json","shield.json","shield_blocking.json","short_dry_grass.json","short_grass.json","shulker_box.json","shulker_shell.json","shulker_spawn_egg.json","silence_armor_trim_smithing_template.json","silverfish_spawn_egg.json","skeleton_horse_spawn_egg.json","skeleton_spawn_egg.json","skull_banner_pattern.json","skull_pottery_sherd.json","slime_ball.json","slime_spawn_egg.json","small_amethyst_bud.json","small_dripleaf.json","sniffer_egg.json","sniffer_spawn_egg.json","snort_pottery_sherd.json","snout_armor_trim_smithing_template.json","snow_golem_spawn_egg.json","snowball.json","soul_campfire.json","soul_lantern.json","soul_torch.json","spectral_arrow.json","spider_eye.json","spider_spawn_egg.json","spire_armor_trim_smithing_template.json","splash_potion.json","spruce_boat.json","spruce_chest_boat.json","spruce_door.json","spruce_hanging_sign.json","spruce_sapling.json","spruce_sign.json","spyglass.json","spyglass_in_hand.json","squid_spawn_egg.json","stick.json","stone_axe.json","stone_hoe.json","stone_pickaxe.json","stone_shovel.json","stone_sword.json","stray_spawn_egg.json","strider_spawn_egg.json","string.json","structure_void.json","sugar.json","sugar_cane.json","sunflower.json","suspicious_stew.json","sweet_berries.json","tadpole_bucket.json","tadpole_spawn_egg.json","tall_dry_grass.json","tall_grass.json","template_banner.json","template_bed.json","template_bundle_open_back.json","template_bundle_open_front.json","template_chest.json","template_music_disc.json","template_shulker_box.json","template_skull.json","tide_armor_trim_smithing_template.json","tipped_arrow.json","tnt_minecart.json","tooting_goat_horn.json","torch.json","torchflower.json","torchflower_seeds.json","totem_of_undying.json","trader_llama_spawn_egg.json","trapped_chest.json","trial_key.json","trident.json","trident_in_hand.json","trident_throwing.json","tripwire_hook.json","tropical_fish.json","tropical_fish_bucket.json","tropical_fish_spawn_egg.json","tube_coral.json","tube_coral_fan.json","turtle_egg.json","turtle_helmet.json","turtle_helmet_amethyst_trim.json","turtle_helmet_copper_trim.json","turtle_helmet_diamond_trim.json","turtle_helmet_emerald_trim.json","turtle_helmet_gold_trim.json","turtle_helmet_iron_trim.json","turtle_helmet_lapis_trim.json","turtle_helmet_netherite_trim.json","turtle_helmet_quartz_trim.json","turtle_helmet_redstone_trim.json","turtle_helmet_resin_trim.json","turtle_scute.json","turtle_spawn_egg.json","twisting_vines.json","vex_armor_trim_smithing_template.json","vex_spawn_egg.json","villager_spawn_egg.json","vindicator_spawn_egg.json","vine.json","wandering_trader_spawn_egg.json","ward_armor_trim_smithing_template.json","warden_spawn_egg.json","warped_door.json","warped_fungus.json","warped_fungus_on_a_stick.json","warped_hanging_sign.json","warped_roots.json","warped_sign.json","water_bucket.json","wayfinder_armor_trim_smithing_template.json","weathered_copper_door.json","weeping_vines.json","wheat.json","wheat_seeds.json","white_bed.json","white_bundle.json","white_bundle_open_back.json","white_bundle_open_front.json","white_candle.json","white_dye.json","white_harness.json","white_shulker_box.json","white_stained_glass_pane.json","white_tulip.json","wild_armor_trim_smithing_template.json","wildflowers.json","wind_charge.json","witch_spawn_egg.json","wither_rose.json","wither_skeleton_spawn_egg.json","wither_spawn_egg.json","wolf_armor.json","wolf_armor_dyed.json","wolf_spawn_egg.json","wooden_axe.json","wooden_hoe.json","wooden_pickaxe.json","wooden_shovel.json","wooden_sword.json","writable_book.json","written_book.json","yellow_bed.json","yellow_bundle.json","yellow_bundle_open_back.json","yellow_bundle_open_front.json","yellow_candle.json","yellow_dye.json","yellow_harness.json","yellow_shulker_box.json","yellow_stained_glass_pane.json","zoglin_spawn_egg.json","zombie_horse_spawn_egg.json","zombie_spawn_egg.json","zombie_villager_spawn_egg.json","zombified_piglin_spawn_egg.json"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/sounds.json b/common-files/src/main/resources/internal/sounds.json index ac1c2a63b..1d92846f1 100644 --- a/common-files/src/main/resources/internal/sounds.json +++ b/common-files/src/main/resources/internal/sounds.json @@ -23696,6 +23696,14 @@ } ] }, + "music_disc.lava_chicken": { + "sounds": [ + { + "name": "records/lava_chicken", + "stream": true + } + ] + }, "music_disc.mall": { "sounds": [ { diff --git a/common-files/src/main/resources/internal/textures/_list.json b/common-files/src/main/resources/internal/textures/_list.json new file mode 100644 index 000000000..23a92e099 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/_list.json @@ -0,0 +1 @@ +{"directories":["block","colormap","effect","entity","environment","font","gui","item","map","misc","mob_effect","painting","particle","trims"],"files":[]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/colormap/_list.json b/common-files/src/main/resources/internal/textures/colormap/_list.json new file mode 100644 index 000000000..fd3061f96 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/colormap/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["dry_foliage.png","foliage.png","grass.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/effect/_list.json b/common-files/src/main/resources/internal/textures/effect/_list.json new file mode 100644 index 000000000..b7964a7e8 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/effect/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["dither.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/_list.json b/common-files/src/main/resources/internal/textures/entity/_list.json new file mode 100644 index 000000000..df6072166 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/_list.json @@ -0,0 +1 @@ +{"directories":["allay","armorstand","axolotl","banner","bear","bed","bee","bell","boat","breeze","camel","cat","chest","chest_boat","chicken","conduit","cow","creaking","creeper","decorated_pot","end_crystal","enderdragon","enderman","equipment","fish","fox","frog","ghast","goat","hoglin","horse","illager","iron_golem","llama","panda","parrot","pig","piglin","player","projectiles","rabbit","sheep","shield","shulker","signs","skeleton","slime","sniffer","spider","squid","strider","tadpole","turtle","villager","warden","wither","wolf","zombie","zombie_villager"],"files":["armadillo.png","banner_base.png","bat.png","beacon_beam.png","blaze.png","dolphin.png","enchanting_table_book.png","end_gateway_beam.png","end_portal.png","endermite.png","experience_orb.png","fishing_hook.png","guardian.png","guardian_beam.png","guardian_elder.png","lead_knot.png","minecart.png","phantom.png","phantom_eyes.png","shield_base.png","shield_base_nopattern.png","silverfish.png","snow_golem.png","spider_eyes.png","trident.png","trident_riptide.png","wandering_trader.png","witch.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/allay/_list.json b/common-files/src/main/resources/internal/textures/entity/allay/_list.json new file mode 100644 index 000000000..4b84e0759 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/allay/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["allay.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/armorstand/_list.json b/common-files/src/main/resources/internal/textures/entity/armorstand/_list.json new file mode 100644 index 000000000..c9664e3db --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/armorstand/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["wood.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/axolotl/_list.json b/common-files/src/main/resources/internal/textures/entity/axolotl/_list.json new file mode 100644 index 000000000..6fcc3c555 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/axolotl/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["axolotl_blue.png","axolotl_cyan.png","axolotl_gold.png","axolotl_lucy.png","axolotl_wild.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/banner/_list.json b/common-files/src/main/resources/internal/textures/entity/banner/_list.json new file mode 100644 index 000000000..02dea7b61 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/banner/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["base.png","border.png","bricks.png","circle.png","creeper.png","cross.png","curly_border.png","diagonal_left.png","diagonal_right.png","diagonal_up_left.png","diagonal_up_right.png","flow.png","flower.png","globe.png","gradient.png","gradient_up.png","guster.png","half_horizontal.png","half_horizontal_bottom.png","half_vertical.png","half_vertical_right.png","mojang.png","piglin.png","rhombus.png","skull.png","small_stripes.png","square_bottom_left.png","square_bottom_right.png","square_top_left.png","square_top_right.png","straight_cross.png","stripe_bottom.png","stripe_center.png","stripe_downleft.png","stripe_downright.png","stripe_left.png","stripe_middle.png","stripe_right.png","stripe_top.png","triangle_bottom.png","triangle_top.png","triangles_bottom.png","triangles_top.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/bear/_list.json b/common-files/src/main/resources/internal/textures/entity/bear/_list.json new file mode 100644 index 000000000..604c3116a --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/bear/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["polarbear.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/bed/_list.json b/common-files/src/main/resources/internal/textures/entity/bed/_list.json new file mode 100644 index 000000000..d8fd32e3e --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/bed/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["black.png","blue.png","brown.png","cyan.png","gray.png","green.png","light_blue.png","light_gray.png","lime.png","magenta.png","orange.png","pink.png","purple.png","red.png","white.png","yellow.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/bee/_list.json b/common-files/src/main/resources/internal/textures/entity/bee/_list.json new file mode 100644 index 000000000..5ae018a30 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/bee/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["bee.png","bee_angry.png","bee_angry_nectar.png","bee_nectar.png","bee_stinger.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/bell/_list.json b/common-files/src/main/resources/internal/textures/entity/bell/_list.json new file mode 100644 index 000000000..159c5031b --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/bell/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["bell_body.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/boat/_list.json b/common-files/src/main/resources/internal/textures/entity/boat/_list.json new file mode 100644 index 000000000..46a5ff587 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/boat/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["acacia.png","bamboo.png","birch.png","cherry.png","dark_oak.png","jungle.png","mangrove.png","oak.png","pale_oak.png","spruce.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/breeze/_list.json b/common-files/src/main/resources/internal/textures/entity/breeze/_list.json new file mode 100644 index 000000000..e681d8b4b --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/breeze/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["breeze.png","breeze_eyes.png","breeze_wind.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/camel/_list.json b/common-files/src/main/resources/internal/textures/entity/camel/_list.json new file mode 100644 index 000000000..770128b32 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/camel/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["camel.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/cat/_list.json b/common-files/src/main/resources/internal/textures/entity/cat/_list.json new file mode 100644 index 000000000..e51c0a28c --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/cat/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["all_black.png","black.png","british_shorthair.png","calico.png","cat_collar.png","jellie.png","ocelot.png","persian.png","ragdoll.png","red.png","siamese.png","tabby.png","white.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/chest/_list.json b/common-files/src/main/resources/internal/textures/entity/chest/_list.json new file mode 100644 index 000000000..16abd3651 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/chest/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["christmas.png","christmas_left.png","christmas_right.png","ender.png","normal.png","normal_left.png","normal_right.png","trapped.png","trapped_left.png","trapped_right.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/chest_boat/_list.json b/common-files/src/main/resources/internal/textures/entity/chest_boat/_list.json new file mode 100644 index 000000000..46a5ff587 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/chest_boat/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["acacia.png","bamboo.png","birch.png","cherry.png","dark_oak.png","jungle.png","mangrove.png","oak.png","pale_oak.png","spruce.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/chicken/_list.json b/common-files/src/main/resources/internal/textures/entity/chicken/_list.json new file mode 100644 index 000000000..7e8ceb878 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/chicken/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["cold_chicken.png","temperate_chicken.png","warm_chicken.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/conduit/_list.json b/common-files/src/main/resources/internal/textures/entity/conduit/_list.json new file mode 100644 index 000000000..932a0a3f9 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/conduit/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["base.png","break_particle.png","cage.png","closed_eye.png","open_eye.png","wind.png","wind.png.mcmeta","wind_vertical.png","wind_vertical.png.mcmeta"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/cow/_list.json b/common-files/src/main/resources/internal/textures/entity/cow/_list.json new file mode 100644 index 000000000..1e5b91ac4 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/cow/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["brown_mooshroom.png","cold_cow.png","red_mooshroom.png","temperate_cow.png","warm_cow.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/creaking/_list.json b/common-files/src/main/resources/internal/textures/entity/creaking/_list.json new file mode 100644 index 000000000..344c44c3b --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/creaking/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["creaking.png","creaking_eyes.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/creeper/_list.json b/common-files/src/main/resources/internal/textures/entity/creeper/_list.json new file mode 100644 index 000000000..c300b9b6f --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/creeper/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["creeper.png","creeper_armor.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/decorated_pot/_list.json b/common-files/src/main/resources/internal/textures/entity/decorated_pot/_list.json new file mode 100644 index 000000000..8dd45ed1e --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/decorated_pot/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["angler_pottery_pattern.png","archer_pottery_pattern.png","arms_up_pottery_pattern.png","blade_pottery_pattern.png","brewer_pottery_pattern.png","burn_pottery_pattern.png","danger_pottery_pattern.png","decorated_pot_base.png","decorated_pot_side.png","explorer_pottery_pattern.png","flow_pottery_pattern.png","friend_pottery_pattern.png","guster_pottery_pattern.png","heart_pottery_pattern.png","heartbreak_pottery_pattern.png","howl_pottery_pattern.png","miner_pottery_pattern.png","mourner_pottery_pattern.png","plenty_pottery_pattern.png","prize_pottery_pattern.png","scrape_pottery_pattern.png","sheaf_pottery_pattern.png","shelter_pottery_pattern.png","skull_pottery_pattern.png","snort_pottery_pattern.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/end_crystal/_list.json b/common-files/src/main/resources/internal/textures/entity/end_crystal/_list.json new file mode 100644 index 000000000..c60d817e2 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/end_crystal/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["end_crystal.png","end_crystal_beam.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/enderdragon/_list.json b/common-files/src/main/resources/internal/textures/entity/enderdragon/_list.json new file mode 100644 index 000000000..c22c3a70f --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/enderdragon/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["dragon.png","dragon_exploding.png","dragon_eyes.png","dragon_fireball.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/enderman/_list.json b/common-files/src/main/resources/internal/textures/entity/enderman/_list.json new file mode 100644 index 000000000..fea7ba8d3 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/enderman/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["enderman.png","enderman_eyes.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/_list.json new file mode 100644 index 000000000..08aee7726 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/_list.json @@ -0,0 +1 @@ +{"directories":["camel_saddle","donkey_saddle","happy_ghast_body","horse_body","horse_saddle","humanoid","humanoid_leggings","llama_body","mule_saddle","pig_saddle","skeleton_horse_saddle","strider_saddle","wings","wolf_body","zombie_horse_saddle"],"files":[]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/camel_saddle/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/camel_saddle/_list.json new file mode 100644 index 000000000..b7f1238d5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/camel_saddle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["saddle.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/donkey_saddle/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/donkey_saddle/_list.json new file mode 100644 index 000000000..b7f1238d5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/donkey_saddle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["saddle.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/happy_ghast_body/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/happy_ghast_body/_list.json new file mode 100644 index 000000000..290eb50e0 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/happy_ghast_body/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["black_harness.png","blue_harness.png","brown_harness.png","cyan_harness.png","gray_harness.png","green_harness.png","light_blue_harness.png","light_gray_harness.png","lime_harness.png","magenta_harness.png","orange_harness.png","pink_harness.png","purple_harness.png","red_harness.png","white_harness.png","yellow_harness.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/horse_body/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/horse_body/_list.json new file mode 100644 index 000000000..72b60f36b --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/horse_body/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["diamond.png","gold.png","iron.png","leather.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/horse_saddle/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/horse_saddle/_list.json new file mode 100644 index 000000000..b7f1238d5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/horse_saddle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["saddle.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/humanoid/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/humanoid/_list.json new file mode 100644 index 000000000..53e6a8655 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/humanoid/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["chainmail.png","diamond.png","gold.png","iron.png","leather.png","leather_overlay.png","netherite.png","turtle_scute.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/humanoid_leggings/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/humanoid_leggings/_list.json new file mode 100644 index 000000000..28c51fb23 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/humanoid_leggings/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["chainmail.png","diamond.png","gold.png","iron.png","leather.png","leather_overlay.png","netherite.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/llama_body/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/llama_body/_list.json new file mode 100644 index 000000000..2593c143d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/llama_body/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["black.png","blue.png","brown.png","cyan.png","gray.png","green.png","light_blue.png","light_gray.png","lime.png","magenta.png","orange.png","pink.png","purple.png","red.png","trader_llama.png","white.png","yellow.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/mule_saddle/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/mule_saddle/_list.json new file mode 100644 index 000000000..b7f1238d5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/mule_saddle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["saddle.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/pig_saddle/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/pig_saddle/_list.json new file mode 100644 index 000000000..b7f1238d5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/pig_saddle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["saddle.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/skeleton_horse_saddle/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/skeleton_horse_saddle/_list.json new file mode 100644 index 000000000..b7f1238d5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/skeleton_horse_saddle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["saddle.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/strider_saddle/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/strider_saddle/_list.json new file mode 100644 index 000000000..b7f1238d5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/strider_saddle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["saddle.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/wings/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/wings/_list.json new file mode 100644 index 000000000..d45d2352d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/wings/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["elytra.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/wolf_body/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/wolf_body/_list.json new file mode 100644 index 000000000..1db139a97 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/wolf_body/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["armadillo_scute.png","armadillo_scute_overlay.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/equipment/zombie_horse_saddle/_list.json b/common-files/src/main/resources/internal/textures/entity/equipment/zombie_horse_saddle/_list.json new file mode 100644 index 000000000..b7f1238d5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/equipment/zombie_horse_saddle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["saddle.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/fish/_list.json b/common-files/src/main/resources/internal/textures/entity/fish/_list.json new file mode 100644 index 000000000..bc6f96eef --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/fish/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["cod.png","pufferfish.png","salmon.png","tropical_a.png","tropical_a_pattern_1.png","tropical_a_pattern_2.png","tropical_a_pattern_3.png","tropical_a_pattern_4.png","tropical_a_pattern_5.png","tropical_a_pattern_6.png","tropical_b.png","tropical_b_pattern_1.png","tropical_b_pattern_2.png","tropical_b_pattern_3.png","tropical_b_pattern_4.png","tropical_b_pattern_5.png","tropical_b_pattern_6.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/fox/_list.json b/common-files/src/main/resources/internal/textures/entity/fox/_list.json new file mode 100644 index 000000000..320e3dae2 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/fox/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["fox.png","fox_sleep.png","snow_fox.png","snow_fox_sleep.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/frog/_list.json b/common-files/src/main/resources/internal/textures/entity/frog/_list.json new file mode 100644 index 000000000..8b019a6f2 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/frog/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["cold_frog.png","temperate_frog.png","warm_frog.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/ghast/_list.json b/common-files/src/main/resources/internal/textures/entity/ghast/_list.json new file mode 100644 index 000000000..d5a30ad8f --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/ghast/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["ghast.png","ghast_shooting.png","happy_ghast.png","happy_ghast_baby.png","happy_ghast_ropes.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/goat/_list.json b/common-files/src/main/resources/internal/textures/entity/goat/_list.json new file mode 100644 index 000000000..58f641aa2 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/goat/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["goat.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/hoglin/_list.json b/common-files/src/main/resources/internal/textures/entity/hoglin/_list.json new file mode 100644 index 000000000..a20b41a1d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/hoglin/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["hoglin.png","zoglin.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/horse/_list.json b/common-files/src/main/resources/internal/textures/entity/horse/_list.json new file mode 100644 index 000000000..9613d1423 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/horse/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["donkey.png","horse_black.png","horse_brown.png","horse_chestnut.png","horse_creamy.png","horse_darkbrown.png","horse_gray.png","horse_markings_blackdots.png","horse_markings_white.png","horse_markings_whitedots.png","horse_markings_whitefield.png","horse_skeleton.png","horse_white.png","horse_zombie.png","mule.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/illager/_list.json b/common-files/src/main/resources/internal/textures/entity/illager/_list.json new file mode 100644 index 000000000..db15d5786 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/illager/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["evoker.png","evoker_fangs.png","illusioner.png","pillager.png","ravager.png","vex.png","vex_charging.png","vindicator.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/iron_golem/_list.json b/common-files/src/main/resources/internal/textures/entity/iron_golem/_list.json new file mode 100644 index 000000000..51c3aa9e3 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/iron_golem/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["iron_golem.png","iron_golem_crackiness_high.png","iron_golem_crackiness_low.png","iron_golem_crackiness_medium.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/llama/_list.json b/common-files/src/main/resources/internal/textures/entity/llama/_list.json new file mode 100644 index 000000000..66e40a5ae --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/llama/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["brown.png","creamy.png","gray.png","spit.png","white.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/panda/_list.json b/common-files/src/main/resources/internal/textures/entity/panda/_list.json new file mode 100644 index 000000000..594b1c532 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/panda/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["aggressive_panda.png","brown_panda.png","lazy_panda.png","panda.png","playful_panda.png","weak_panda.png","worried_panda.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/parrot/_list.json b/common-files/src/main/resources/internal/textures/entity/parrot/_list.json new file mode 100644 index 000000000..4f63b2e79 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/parrot/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["parrot_blue.png","parrot_green.png","parrot_grey.png","parrot_red_blue.png","parrot_yellow_blue.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/pig/_list.json b/common-files/src/main/resources/internal/textures/entity/pig/_list.json new file mode 100644 index 000000000..72a5cf3c5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/pig/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["cold_pig.png","temperate_pig.png","warm_pig.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/piglin/_list.json b/common-files/src/main/resources/internal/textures/entity/piglin/_list.json new file mode 100644 index 000000000..245d48595 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/piglin/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["piglin.png","piglin_brute.png","zombified_piglin.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/player/_list.json b/common-files/src/main/resources/internal/textures/entity/player/_list.json new file mode 100644 index 000000000..281e580c3 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/player/_list.json @@ -0,0 +1 @@ +{"directories":["slim","wide"],"files":[]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/player/slim/_list.json b/common-files/src/main/resources/internal/textures/entity/player/slim/_list.json new file mode 100644 index 000000000..c92ed32f5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/player/slim/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["alex.png","ari.png","efe.png","kai.png","makena.png","noor.png","steve.png","sunny.png","zuri.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/player/wide/_list.json b/common-files/src/main/resources/internal/textures/entity/player/wide/_list.json new file mode 100644 index 000000000..c92ed32f5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/player/wide/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["alex.png","ari.png","efe.png","kai.png","makena.png","noor.png","steve.png","sunny.png","zuri.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/projectiles/_list.json b/common-files/src/main/resources/internal/textures/entity/projectiles/_list.json new file mode 100644 index 000000000..55bf4ee20 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/projectiles/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["arrow.png","spectral_arrow.png","tipped_arrow.png","wind_charge.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/rabbit/_list.json b/common-files/src/main/resources/internal/textures/entity/rabbit/_list.json new file mode 100644 index 000000000..7ff22481e --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/rabbit/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["black.png","brown.png","caerbannog.png","gold.png","salt.png","toast.png","white.png","white_splotched.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/sheep/_list.json b/common-files/src/main/resources/internal/textures/entity/sheep/_list.json new file mode 100644 index 000000000..7545044da --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/sheep/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["sheep.png","sheep_wool.png","sheep_wool_undercoat.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/shield/_list.json b/common-files/src/main/resources/internal/textures/entity/shield/_list.json new file mode 100644 index 000000000..02dea7b61 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/shield/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["base.png","border.png","bricks.png","circle.png","creeper.png","cross.png","curly_border.png","diagonal_left.png","diagonal_right.png","diagonal_up_left.png","diagonal_up_right.png","flow.png","flower.png","globe.png","gradient.png","gradient_up.png","guster.png","half_horizontal.png","half_horizontal_bottom.png","half_vertical.png","half_vertical_right.png","mojang.png","piglin.png","rhombus.png","skull.png","small_stripes.png","square_bottom_left.png","square_bottom_right.png","square_top_left.png","square_top_right.png","straight_cross.png","stripe_bottom.png","stripe_center.png","stripe_downleft.png","stripe_downright.png","stripe_left.png","stripe_middle.png","stripe_right.png","stripe_top.png","triangle_bottom.png","triangle_top.png","triangles_bottom.png","triangles_top.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/shulker/_list.json b/common-files/src/main/resources/internal/textures/entity/shulker/_list.json new file mode 100644 index 000000000..e69a9ac97 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/shulker/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["shulker.png","shulker_black.png","shulker_blue.png","shulker_brown.png","shulker_cyan.png","shulker_gray.png","shulker_green.png","shulker_light_blue.png","shulker_light_gray.png","shulker_lime.png","shulker_magenta.png","shulker_orange.png","shulker_pink.png","shulker_purple.png","shulker_red.png","shulker_white.png","shulker_yellow.png","spark.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/signs/_list.json b/common-files/src/main/resources/internal/textures/entity/signs/_list.json new file mode 100644 index 000000000..234a278ed --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/signs/_list.json @@ -0,0 +1 @@ +{"directories":["hanging"],"files":["acacia.png","bamboo.png","birch.png","cherry.png","crimson.png","dark_oak.png","jungle.png","mangrove.png","oak.png","pale_oak.png","spruce.png","warped.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/signs/hanging/_list.json b/common-files/src/main/resources/internal/textures/entity/signs/hanging/_list.json new file mode 100644 index 000000000..01b318f31 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/signs/hanging/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["acacia.png","bamboo.png","birch.png","cherry.png","crimson.png","dark_oak.png","jungle.png","mangrove.png","oak.png","pale_oak.png","spruce.png","warped.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/skeleton/_list.json b/common-files/src/main/resources/internal/textures/entity/skeleton/_list.json new file mode 100644 index 000000000..12a88023d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/skeleton/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["bogged.png","bogged_overlay.png","skeleton.png","stray.png","stray_overlay.png","wither_skeleton.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/slime/_list.json b/common-files/src/main/resources/internal/textures/entity/slime/_list.json new file mode 100644 index 000000000..63730a800 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/slime/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["magmacube.png","slime.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/sniffer/_list.json b/common-files/src/main/resources/internal/textures/entity/sniffer/_list.json new file mode 100644 index 000000000..3897fab4d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/sniffer/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["sniffer.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/spider/_list.json b/common-files/src/main/resources/internal/textures/entity/spider/_list.json new file mode 100644 index 000000000..f45ff752b --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/spider/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["cave_spider.png","spider.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/squid/_list.json b/common-files/src/main/resources/internal/textures/entity/squid/_list.json new file mode 100644 index 000000000..74da4a96d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/squid/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["glow_squid.png","squid.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/strider/_list.json b/common-files/src/main/resources/internal/textures/entity/strider/_list.json new file mode 100644 index 000000000..2e88186eb --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/strider/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["strider.png","strider_cold.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/tadpole/_list.json b/common-files/src/main/resources/internal/textures/entity/tadpole/_list.json new file mode 100644 index 000000000..a95050a5f --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/tadpole/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["tadpole.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/turtle/_list.json b/common-files/src/main/resources/internal/textures/entity/turtle/_list.json new file mode 100644 index 000000000..ddb182b27 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/turtle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["big_sea_turtle.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/villager/_list.json b/common-files/src/main/resources/internal/textures/entity/villager/_list.json new file mode 100644 index 000000000..430228faa --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/villager/_list.json @@ -0,0 +1 @@ +{"directories":["profession","profession_level","type"],"files":["villager.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/villager/profession/_list.json b/common-files/src/main/resources/internal/textures/entity/villager/profession/_list.json new file mode 100644 index 000000000..fab07c7a9 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/villager/profession/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["armorer.png","butcher.png","butcher.png.mcmeta","cartographer.png","cleric.png","farmer.png","farmer.png.mcmeta","fisherman.png","fisherman.png.mcmeta","fletcher.png","fletcher.png.mcmeta","leatherworker.png","librarian.png","librarian.png.mcmeta","mason.png","nitwit.png","shepherd.png","shepherd.png.mcmeta","toolsmith.png","weaponsmith.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/villager/profession_level/_list.json b/common-files/src/main/resources/internal/textures/entity/villager/profession_level/_list.json new file mode 100644 index 000000000..f7755ab5d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/villager/profession_level/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["diamond.png","emerald.png","gold.png","iron.png","stone.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/villager/type/_list.json b/common-files/src/main/resources/internal/textures/entity/villager/type/_list.json new file mode 100644 index 000000000..955f2f36f --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/villager/type/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["desert.png","desert.png.mcmeta","jungle.png","plains.png","savanna.png","snow.png","snow.png.mcmeta","swamp.png","taiga.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/warden/_list.json b/common-files/src/main/resources/internal/textures/entity/warden/_list.json new file mode 100644 index 000000000..af8aee6ab --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/warden/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["warden.png","warden_bioluminescent_layer.png","warden_heart.png","warden_pulsating_spots_1.png","warden_pulsating_spots_2.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/wither/_list.json b/common-files/src/main/resources/internal/textures/entity/wither/_list.json new file mode 100644 index 000000000..6f8da04a6 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/wither/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["wither.png","wither_armor.png","wither_invulnerable.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/wolf/_list.json b/common-files/src/main/resources/internal/textures/entity/wolf/_list.json new file mode 100644 index 000000000..60a55f125 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/wolf/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["wolf.png","wolf_angry.png","wolf_armor_crackiness_high.png","wolf_armor_crackiness_low.png","wolf_armor_crackiness_medium.png","wolf_ashen.png","wolf_ashen_angry.png","wolf_ashen_tame.png","wolf_black.png","wolf_black_angry.png","wolf_black_tame.png","wolf_chestnut.png","wolf_chestnut_angry.png","wolf_chestnut_tame.png","wolf_collar.png","wolf_rusty.png","wolf_rusty_angry.png","wolf_rusty_tame.png","wolf_snowy.png","wolf_snowy_angry.png","wolf_snowy_tame.png","wolf_spotted.png","wolf_spotted_angry.png","wolf_spotted_tame.png","wolf_striped.png","wolf_striped_angry.png","wolf_striped_tame.png","wolf_tame.png","wolf_woods.png","wolf_woods_angry.png","wolf_woods_tame.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/zombie/_list.json b/common-files/src/main/resources/internal/textures/entity/zombie/_list.json new file mode 100644 index 000000000..6b15d775b --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/zombie/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["drowned.png","drowned_outer_layer.png","husk.png","zombie.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/zombie_villager/_list.json b/common-files/src/main/resources/internal/textures/entity/zombie_villager/_list.json new file mode 100644 index 000000000..bb0feeea4 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/zombie_villager/_list.json @@ -0,0 +1 @@ +{"directories":["profession","profession_level","type"],"files":["zombie_villager.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/zombie_villager/profession/_list.json b/common-files/src/main/resources/internal/textures/entity/zombie_villager/profession/_list.json new file mode 100644 index 000000000..fab07c7a9 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/zombie_villager/profession/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["armorer.png","butcher.png","butcher.png.mcmeta","cartographer.png","cleric.png","farmer.png","farmer.png.mcmeta","fisherman.png","fisherman.png.mcmeta","fletcher.png","fletcher.png.mcmeta","leatherworker.png","librarian.png","librarian.png.mcmeta","mason.png","nitwit.png","shepherd.png","shepherd.png.mcmeta","toolsmith.png","weaponsmith.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/zombie_villager/profession_level/_list.json b/common-files/src/main/resources/internal/textures/entity/zombie_villager/profession_level/_list.json new file mode 100644 index 000000000..f7755ab5d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/zombie_villager/profession_level/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["diamond.png","emerald.png","gold.png","iron.png","stone.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/entity/zombie_villager/type/_list.json b/common-files/src/main/resources/internal/textures/entity/zombie_villager/type/_list.json new file mode 100644 index 000000000..9377957e7 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/entity/zombie_villager/type/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["desert.png","jungle.png","plains.png","savanna.png","snow.png","swamp.png","taiga.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/environment/_list.json b/common-files/src/main/resources/internal/textures/environment/_list.json new file mode 100644 index 000000000..163742403 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/environment/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["clouds.png","end_sky.png","moon_phases.png","rain.png","snow.png","sun.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/_list.json b/common-files/src/main/resources/internal/textures/gui/_list.json new file mode 100644 index 000000000..82692295c --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/_list.json @@ -0,0 +1 @@ +{"directories":["advancements","container","hanging_signs","presets","realms","sprites","title"],"files":["book.png","demo_background.png","footer_separator.png","header_separator.png","inworld_footer_separator.png","inworld_header_separator.png","inworld_menu_background.png","inworld_menu_list_background.png","menu_background.png","menu_list_background.png","recipe_book.png","tab_header_background.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/advancements/_list.json b/common-files/src/main/resources/internal/textures/gui/advancements/_list.json new file mode 100644 index 000000000..1e94e545e --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/advancements/_list.json @@ -0,0 +1 @@ +{"directories":["backgrounds"],"files":["window.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/advancements/backgrounds/_list.json b/common-files/src/main/resources/internal/textures/gui/advancements/backgrounds/_list.json new file mode 100644 index 000000000..6907edff2 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/advancements/backgrounds/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["adventure.png","end.png","husbandry.png","nether.png","stone.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/container/_list.json b/common-files/src/main/resources/internal/textures/gui/container/_list.json new file mode 100644 index 000000000..f94e1bca8 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/container/_list.json @@ -0,0 +1 @@ +{"directories":["creative_inventory"],"files":["anvil.png","beacon.png","blast_furnace.png","brewing_stand.png","cartography_table.png","crafter.png","crafting_table.png","dispenser.png","enchanting_table.png","furnace.png","gamemode_switcher.png","generic_54.png","grindstone.png","hopper.png","horse.png","inventory.png","loom.png","shulker_box.png","smithing.png","smoker.png","stonecutter.png","villager.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/container/creative_inventory/_list.json b/common-files/src/main/resources/internal/textures/gui/container/creative_inventory/_list.json new file mode 100644 index 000000000..1b959be88 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/container/creative_inventory/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["tab_inventory.png","tab_item_search.png","tab_items.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/hanging_signs/_list.json b/common-files/src/main/resources/internal/textures/gui/hanging_signs/_list.json new file mode 100644 index 000000000..01b318f31 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/hanging_signs/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["acacia.png","bamboo.png","birch.png","cherry.png","crimson.png","dark_oak.png","jungle.png","mangrove.png","oak.png","pale_oak.png","spruce.png","warped.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/presets/_list.json b/common-files/src/main/resources/internal/textures/gui/presets/_list.json new file mode 100644 index 000000000..4e31f7674 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/presets/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["isles.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/realms/_list.json b/common-files/src/main/resources/internal/textures/gui/realms/_list.json new file mode 100644 index 000000000..968bfc415 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/realms/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["adventure.png","empty_frame.png","experience.png","inspiration.png","new_world.png","no_realms.png","snapshot_realms.png","survival_spawn.png","upload.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/_list.json new file mode 100644 index 000000000..fb88aca52 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/_list.json @@ -0,0 +1 @@ +{"directories":["advancements","boss_bar","container","dialog","gamemode_switcher","hud","icon","notification","pending_invite","player_list","popup","realm_status","recipe_book","server_list","social_interactions","spectator","statistics","toast","tooltip","transferable_list","widget","world_list"],"files":[]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/advancements/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/advancements/_list.json new file mode 100644 index 000000000..479c28d1d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/advancements/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["box_obtained.png","box_obtained.png.mcmeta","box_unobtained.png","box_unobtained.png.mcmeta","challenge_frame_obtained.png","challenge_frame_unobtained.png","goal_frame_obtained.png","goal_frame_unobtained.png","tab_above_left.png","tab_above_left_selected.png","tab_above_middle.png","tab_above_middle_selected.png","tab_above_right.png","tab_above_right_selected.png","tab_below_left.png","tab_below_left_selected.png","tab_below_middle.png","tab_below_middle_selected.png","tab_below_right.png","tab_below_right_selected.png","tab_left_bottom.png","tab_left_bottom_selected.png","tab_left_middle.png","tab_left_middle_selected.png","tab_left_top.png","tab_left_top_selected.png","tab_right_bottom.png","tab_right_bottom_selected.png","tab_right_middle.png","tab_right_middle_selected.png","tab_right_top.png","tab_right_top_selected.png","task_frame_obtained.png","task_frame_unobtained.png","title_box.png","title_box.png.mcmeta"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/boss_bar/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/boss_bar/_list.json new file mode 100644 index 000000000..20ca628e6 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/boss_bar/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["blue_background.png","blue_progress.png","green_background.png","green_progress.png","notched_10_background.png","notched_10_progress.png","notched_12_background.png","notched_12_progress.png","notched_20_background.png","notched_20_progress.png","notched_6_background.png","notched_6_progress.png","pink_background.png","pink_progress.png","purple_background.png","purple_progress.png","red_background.png","red_progress.png","white_background.png","white_progress.png","yellow_background.png","yellow_progress.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/_list.json new file mode 100644 index 000000000..49fb80ef2 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/_list.json @@ -0,0 +1 @@ +{"directories":["anvil","beacon","blast_furnace","brewing_stand","bundle","cartography_table","crafter","creative_inventory","enchanting_table","furnace","grindstone","horse","inventory","loom","slot","smithing","smoker","stonecutter","villager"],"files":["slot.png","slot_highlight_back.png","slot_highlight_back.png.mcmeta","slot_highlight_front.png","slot_highlight_front.png.mcmeta"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/anvil/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/anvil/_list.json new file mode 100644 index 000000000..2cd44e6ee --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/anvil/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["error.png","text_field.png","text_field_disabled.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/beacon/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/beacon/_list.json new file mode 100644 index 000000000..4e8ea5c0b --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/beacon/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["button.png","button_disabled.png","button_highlighted.png","button_selected.png","cancel.png","confirm.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/blast_furnace/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/blast_furnace/_list.json new file mode 100644 index 000000000..f891fb3d7 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/blast_furnace/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["burn_progress.png","lit_progress.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/brewing_stand/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/brewing_stand/_list.json new file mode 100644 index 000000000..8de2f8377 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/brewing_stand/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["brew_progress.png","bubbles.png","fuel_length.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/bundle/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/bundle/_list.json new file mode 100644 index 000000000..046222c39 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/bundle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["bundle_progressbar_border.png","bundle_progressbar_border.png.mcmeta","bundle_progressbar_fill.png","bundle_progressbar_fill.png.mcmeta","bundle_progressbar_full.png","bundle_progressbar_full.png.mcmeta","slot_background.png","slot_background.png.mcmeta","slot_highlight_back.png","slot_highlight_back.png.mcmeta","slot_highlight_front.png","slot_highlight_front.png.mcmeta"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/cartography_table/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/cartography_table/_list.json new file mode 100644 index 000000000..f53282e48 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/cartography_table/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["duplicated_map.png","error.png","locked.png","map.png","scaled_map.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/crafter/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/crafter/_list.json new file mode 100644 index 000000000..e0a16fa8a --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/crafter/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["disabled_slot.png","powered_redstone.png","unpowered_redstone.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/creative_inventory/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/creative_inventory/_list.json new file mode 100644 index 000000000..7c5c38f45 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/creative_inventory/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["scroller.png","scroller_disabled.png","tab_bottom_selected_1.png","tab_bottom_selected_2.png","tab_bottom_selected_3.png","tab_bottom_selected_4.png","tab_bottom_selected_5.png","tab_bottom_selected_6.png","tab_bottom_selected_7.png","tab_bottom_unselected_1.png","tab_bottom_unselected_2.png","tab_bottom_unselected_3.png","tab_bottom_unselected_4.png","tab_bottom_unselected_5.png","tab_bottom_unselected_6.png","tab_bottom_unselected_7.png","tab_top_selected_1.png","tab_top_selected_2.png","tab_top_selected_3.png","tab_top_selected_4.png","tab_top_selected_5.png","tab_top_selected_6.png","tab_top_selected_7.png","tab_top_unselected_1.png","tab_top_unselected_2.png","tab_top_unselected_3.png","tab_top_unselected_4.png","tab_top_unselected_5.png","tab_top_unselected_6.png","tab_top_unselected_7.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/enchanting_table/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/enchanting_table/_list.json new file mode 100644 index 000000000..d3d611f13 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/enchanting_table/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["enchantment_slot.png","enchantment_slot_disabled.png","enchantment_slot_highlighted.png","level_1.png","level_1_disabled.png","level_2.png","level_2_disabled.png","level_3.png","level_3_disabled.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/furnace/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/furnace/_list.json new file mode 100644 index 000000000..f891fb3d7 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/furnace/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["burn_progress.png","lit_progress.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/grindstone/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/grindstone/_list.json new file mode 100644 index 000000000..74845b898 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/grindstone/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["error.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/horse/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/horse/_list.json new file mode 100644 index 000000000..1526e5cb1 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/horse/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["chest_slots.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/inventory/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/inventory/_list.json new file mode 100644 index 000000000..431a683d3 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/inventory/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["effect_background_large.png","effect_background_small.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/loom/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/loom/_list.json new file mode 100644 index 000000000..f4d9ef802 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/loom/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["error.png","pattern.png","pattern_highlighted.png","pattern_selected.png","scroller.png","scroller_disabled.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/slot/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/slot/_list.json new file mode 100644 index 000000000..d10743a6c --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/slot/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["amethyst_shard.png","axe.png","banner.png","banner_pattern.png","boots.png","brewing_fuel.png","chestplate.png","diamond.png","dye.png","emerald.png","helmet.png","hoe.png","horse_armor.png","ingot.png","lapis_lazuli.png","leggings.png","llama_armor.png","pickaxe.png","potion.png","quartz.png","redstone_dust.png","saddle.png","shield.png","shovel.png","smithing_template_armor_trim.png","smithing_template_netherite_upgrade.png","sword.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/smithing/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/smithing/_list.json new file mode 100644 index 000000000..74845b898 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/smithing/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["error.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/smoker/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/smoker/_list.json new file mode 100644 index 000000000..f891fb3d7 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/smoker/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["burn_progress.png","lit_progress.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/stonecutter/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/stonecutter/_list.json new file mode 100644 index 000000000..e623a34d6 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/stonecutter/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["recipe.png","recipe_highlighted.png","recipe_selected.png","scroller.png","scroller_disabled.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/container/villager/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/container/villager/_list.json new file mode 100644 index 000000000..83242e7c1 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/container/villager/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["discount_strikethrough.png","experience_bar_background.png","experience_bar_current.png","experience_bar_result.png","out_of_stock.png","scroller.png","scroller_disabled.png","trade_arrow.png","trade_arrow_out_of_stock.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/dialog/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/dialog/_list.json new file mode 100644 index 000000000..99850b9bf --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/dialog/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["warning_button.png","warning_button_disabled.png","warning_button_highlighted.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/gamemode_switcher/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/gamemode_switcher/_list.json new file mode 100644 index 000000000..e9fca1783 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/gamemode_switcher/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["selection.png","slot.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/hud/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/hud/_list.json new file mode 100644 index 000000000..832cc2466 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/hud/_list.json @@ -0,0 +1 @@ +{"directories":["heart","locator_bar_dot"],"files":["air.png","air_bursting.png","air_empty.png","armor_empty.png","armor_full.png","armor_half.png","crosshair.png","crosshair_attack_indicator_background.png","crosshair_attack_indicator_full.png","crosshair_attack_indicator_progress.png","effect_background.png","effect_background_ambient.png","experience_bar_background.png","experience_bar_progress.png","food_empty.png","food_empty_hunger.png","food_full.png","food_full_hunger.png","food_half.png","food_half_hunger.png","hotbar.png","hotbar_attack_indicator_background.png","hotbar_attack_indicator_progress.png","hotbar_offhand_left.png","hotbar_offhand_right.png","hotbar_selection.png","jump_bar_background.png","jump_bar_cooldown.png","jump_bar_progress.png","locator_bar_arrow_down.png","locator_bar_arrow_down.png.mcmeta","locator_bar_arrow_up.png","locator_bar_arrow_up.png.mcmeta","locator_bar_background.png","locator_bar_background.png.mcmeta"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/hud/heart/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/hud/heart/_list.json new file mode 100644 index 000000000..3db88fec5 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/hud/heart/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["absorbing_full.png","absorbing_full_blinking.png","absorbing_half.png","absorbing_half_blinking.png","absorbing_hardcore_full.png","absorbing_hardcore_full_blinking.png","absorbing_hardcore_half.png","absorbing_hardcore_half_blinking.png","container.png","container_blinking.png","container_hardcore.png","container_hardcore_blinking.png","frozen_full.png","frozen_full_blinking.png","frozen_half.png","frozen_half_blinking.png","frozen_hardcore_full.png","frozen_hardcore_full_blinking.png","frozen_hardcore_half.png","frozen_hardcore_half_blinking.png","full.png","full_blinking.png","half.png","half_blinking.png","hardcore_full.png","hardcore_full_blinking.png","hardcore_half.png","hardcore_half_blinking.png","poisoned_full.png","poisoned_full_blinking.png","poisoned_half.png","poisoned_half_blinking.png","poisoned_hardcore_full.png","poisoned_hardcore_full_blinking.png","poisoned_hardcore_half.png","poisoned_hardcore_half_blinking.png","vehicle_container.png","vehicle_full.png","vehicle_half.png","withered_full.png","withered_full_blinking.png","withered_half.png","withered_half_blinking.png","withered_hardcore_full.png","withered_hardcore_full_blinking.png","withered_hardcore_half.png","withered_hardcore_half_blinking.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/hud/locator_bar_dot/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/hud/locator_bar_dot/_list.json new file mode 100644 index 000000000..a6dedcc7c --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/hud/locator_bar_dot/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["bowtie.png","default_0.png","default_1.png","default_2.png","default_3.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/icon/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/icon/_list.json new file mode 100644 index 000000000..58af4118c --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/icon/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["accessibility.png","chat_modified.png","checkmark.png","draft_report.png","info.png","invite.png","language.png","link.png","link_highlighted.png","music_notes.png","music_notes.png.mcmeta","new_realm.png","news.png","ping_1.png","ping_2.png","ping_3.png","ping_4.png","ping_5.png","ping_unknown.png","search.png","trial_available.png","trial_available.png.mcmeta","unseen_notification.png","video_link.png","video_link_highlighted.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/notification/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/notification/_list.json new file mode 100644 index 000000000..2bbcba83c --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/notification/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["1.png","2.png","3.png","4.png","5.png","more.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/pending_invite/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/pending_invite/_list.json new file mode 100644 index 000000000..02f121666 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/pending_invite/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["accept.png","accept_highlighted.png","reject.png","reject_highlighted.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/player_list/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/player_list/_list.json new file mode 100644 index 000000000..32cbc9e1e --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/player_list/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["make_operator.png","remove_operator.png","remove_player.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/popup/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/popup/_list.json new file mode 100644 index 000000000..c43ec2824 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/popup/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["background.png","background.png.mcmeta"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/realm_status/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/realm_status/_list.json new file mode 100644 index 000000000..89ac5b05a --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/realm_status/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["closed.png","expired.png","expires_soon.png","expires_soon.png.mcmeta","open.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/recipe_book/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/recipe_book/_list.json new file mode 100644 index 000000000..3be688a32 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/recipe_book/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["button.png","button_highlighted.png","crafting_overlay.png","crafting_overlay_disabled.png","crafting_overlay_disabled_highlighted.png","crafting_overlay_highlighted.png","filter_disabled.png","filter_disabled_highlighted.png","filter_enabled.png","filter_enabled_highlighted.png","furnace_filter_disabled.png","furnace_filter_disabled_highlighted.png","furnace_filter_enabled.png","furnace_filter_enabled_highlighted.png","furnace_overlay.png","furnace_overlay_disabled.png","furnace_overlay_disabled_highlighted.png","furnace_overlay_highlighted.png","overlay_recipe.png","overlay_recipe.png.mcmeta","page_backward.png","page_backward_highlighted.png","page_forward.png","page_forward_highlighted.png","slot_craftable.png","slot_many_craftable.png","slot_many_uncraftable.png","slot_uncraftable.png","tab.png","tab_selected.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/server_list/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/server_list/_list.json new file mode 100644 index 000000000..b0a5b11ce --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/server_list/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["incompatible.png","join.png","join_highlighted.png","move_down.png","move_down_highlighted.png","move_up.png","move_up_highlighted.png","ping_1.png","ping_2.png","ping_3.png","ping_4.png","ping_5.png","pinging_1.png","pinging_2.png","pinging_3.png","pinging_4.png","pinging_5.png","unreachable.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/social_interactions/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/social_interactions/_list.json new file mode 100644 index 000000000..174cdea8d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/social_interactions/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["background.png","background.png.mcmeta","mute_button.png","mute_button_highlighted.png","report_button.png","report_button_disabled.png","report_button_highlighted.png","unmute_button.png","unmute_button_highlighted.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/spectator/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/spectator/_list.json new file mode 100644 index 000000000..ffcb28c96 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/spectator/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["close.png","scroll_left.png","scroll_right.png","teleport_to_player.png","teleport_to_team.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/statistics/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/statistics/_list.json new file mode 100644 index 000000000..4309efab4 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/statistics/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["block_mined.png","header.png","item_broken.png","item_crafted.png","item_dropped.png","item_picked_up.png","item_used.png","sort_down.png","sort_up.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/toast/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/toast/_list.json new file mode 100644 index 000000000..c88f5be25 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/toast/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["advancement.png","mouse.png","movement_keys.png","now_playing.png","now_playing.png.mcmeta","recipe.png","recipe_book.png","right_click.png","social_interactions.png","system.png","system.png.mcmeta","tree.png","tutorial.png","tutorial.png.mcmeta","wooden_planks.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/tooltip/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/tooltip/_list.json new file mode 100644 index 000000000..d8471254d --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/tooltip/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["background.png","background.png.mcmeta","frame.png","frame.png.mcmeta"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/transferable_list/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/transferable_list/_list.json new file mode 100644 index 000000000..95e0eac44 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/transferable_list/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["move_down.png","move_down_highlighted.png","move_up.png","move_up_highlighted.png","select.png","select_highlighted.png","unselect.png","unselect_highlighted.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/widget/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/widget/_list.json new file mode 100644 index 000000000..db3873f6c --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/widget/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["button.png","button.png.mcmeta","button_disabled.png","button_disabled.png.mcmeta","button_highlighted.png","button_highlighted.png.mcmeta","checkbox.png","checkbox_highlighted.png","checkbox_selected.png","checkbox_selected_highlighted.png","cross_button.png","cross_button_highlighted.png","locked_button.png","locked_button_disabled.png","locked_button_highlighted.png","page_backward.png","page_backward_highlighted.png","page_forward.png","page_forward_highlighted.png","scroller.png","scroller.png.mcmeta","scroller_background.png","scroller_background.png.mcmeta","slider.png","slider.png.mcmeta","slider_handle.png","slider_handle.png.mcmeta","slider_handle_highlighted.png","slider_handle_highlighted.png.mcmeta","slider_highlighted.png","slider_highlighted.png.mcmeta","slot_frame.png","tab.png","tab.png.mcmeta","tab_highlighted.png","tab_highlighted.png.mcmeta","tab_selected.png","tab_selected.png.mcmeta","tab_selected_highlighted.png","tab_selected_highlighted.png.mcmeta","text_field.png","text_field.png.mcmeta","text_field_highlighted.png","text_field_highlighted.png.mcmeta","unlocked_button.png","unlocked_button_disabled.png","unlocked_button_highlighted.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/sprites/world_list/_list.json b/common-files/src/main/resources/internal/textures/gui/sprites/world_list/_list.json new file mode 100644 index 000000000..421742c94 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/sprites/world_list/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["error.png","error_highlighted.png","join.png","join_highlighted.png","marked_join.png","marked_join_highlighted.png","warning.png","warning_highlighted.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/title/_list.json b/common-files/src/main/resources/internal/textures/gui/title/_list.json new file mode 100644 index 000000000..632a4a79a --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/title/_list.json @@ -0,0 +1 @@ +{"directories":["background"],"files":["edition.png","minceraft.png","minecraft.png","mojangstudios.png","realms.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/gui/title/background/_list.json b/common-files/src/main/resources/internal/textures/gui/title/background/_list.json new file mode 100644 index 000000000..7fb955917 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/gui/title/background/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["panorama_0.png","panorama_1.png","panorama_2.png","panorama_3.png","panorama_4.png","panorama_5.png","panorama_overlay.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/item/_list.json b/common-files/src/main/resources/internal/textures/item/_list.json index 1b60526e8..f66a314cb 100644 --- a/common-files/src/main/resources/internal/textures/item/_list.json +++ b/common-files/src/main/resources/internal/textures/item/_list.json @@ -1 +1 @@ -{"directories":[],"files":["acacia_boat.png","acacia_chest_boat.png","acacia_door.png","acacia_hanging_sign.png","acacia_sign.png","allay_spawn_egg.png","amethyst_shard.png","angler_pottery_sherd.png","apple.png","archer_pottery_sherd.png","armadillo_scute.png","armadillo_spawn_egg.png","armor_stand.png","arms_up_pottery_sherd.png","arrow.png","axolotl_bucket.png","axolotl_spawn_egg.png","baked_potato.png","bamboo.png","bamboo_chest_raft.png","bamboo_door.png","bamboo_hanging_sign.png","bamboo_raft.png","bamboo_sign.png","barrier.png","bat_spawn_egg.png","bee_spawn_egg.png","beef.png","beetroot.png","beetroot_seeds.png","beetroot_soup.png","bell.png","birch_boat.png","birch_chest_boat.png","birch_door.png","birch_hanging_sign.png","birch_sign.png","black_bundle.png","black_bundle_open_back.png","black_bundle_open_front.png","black_candle.png","black_dye.png","black_harness.png","blade_pottery_sherd.png","blaze_powder.png","blaze_rod.png","blaze_spawn_egg.png","blue_bundle.png","blue_bundle_open_back.png","blue_bundle_open_front.png","blue_candle.png","blue_dye.png","blue_egg.png","blue_harness.png","bogged_spawn_egg.png","bolt_armor_trim_smithing_template.png","bone.png","bone_meal.png","book.png","bordure_indented_banner_pattern.png","bow.png","bow_pulling_0.png","bow_pulling_1.png","bow_pulling_2.png","bowl.png","bread.png","breeze_rod.png","breeze_spawn_egg.png","brewer_pottery_sherd.png","brewing_stand.png","brick.png","brown_bundle.png","brown_bundle_open_back.png","brown_bundle_open_front.png","brown_candle.png","brown_dye.png","brown_egg.png","brown_harness.png","brush.png","bucket.png","bundle.png","bundle_open_back.png","bundle_open_front.png","burn_pottery_sherd.png","cake.png","camel_spawn_egg.png","campfire.png","candle.png","carrot.png","carrot_on_a_stick.png","cat_spawn_egg.png","cauldron.png","cave_spider_spawn_egg.png","chain.png","chainmail_boots.png","chainmail_chestplate.png","chainmail_helmet.png","chainmail_leggings.png","charcoal.png","cherry_boat.png","cherry_chest_boat.png","cherry_door.png","cherry_hanging_sign.png","cherry_sign.png","chest_minecart.png","chicken.png","chicken_spawn_egg.png","chorus_fruit.png","clay_ball.png","clock_00.png","clock_01.png","clock_02.png","clock_03.png","clock_04.png","clock_05.png","clock_06.png","clock_07.png","clock_08.png","clock_09.png","clock_10.png","clock_11.png","clock_12.png","clock_13.png","clock_14.png","clock_15.png","clock_16.png","clock_17.png","clock_18.png","clock_19.png","clock_20.png","clock_21.png","clock_22.png","clock_23.png","clock_24.png","clock_25.png","clock_26.png","clock_27.png","clock_28.png","clock_29.png","clock_30.png","clock_31.png","clock_32.png","clock_33.png","clock_34.png","clock_35.png","clock_36.png","clock_37.png","clock_38.png","clock_39.png","clock_40.png","clock_41.png","clock_42.png","clock_43.png","clock_44.png","clock_45.png","clock_46.png","clock_47.png","clock_48.png","clock_49.png","clock_50.png","clock_51.png","clock_52.png","clock_53.png","clock_54.png","clock_55.png","clock_56.png","clock_57.png","clock_58.png","clock_59.png","clock_60.png","clock_61.png","clock_62.png","clock_63.png","coal.png","coast_armor_trim_smithing_template.png","cocoa_beans.png","cod.png","cod_bucket.png","cod_spawn_egg.png","command_block_minecart.png","comparator.png","compass_00.png","compass_01.png","compass_02.png","compass_03.png","compass_04.png","compass_05.png","compass_06.png","compass_07.png","compass_08.png","compass_09.png","compass_10.png","compass_11.png","compass_12.png","compass_13.png","compass_14.png","compass_15.png","compass_16.png","compass_17.png","compass_18.png","compass_19.png","compass_20.png","compass_21.png","compass_22.png","compass_23.png","compass_24.png","compass_25.png","compass_26.png","compass_27.png","compass_28.png","compass_29.png","compass_30.png","compass_31.png","cooked_beef.png","cooked_chicken.png","cooked_cod.png","cooked_mutton.png","cooked_porkchop.png","cooked_rabbit.png","cooked_salmon.png","cookie.png","copper_door.png","copper_ingot.png","cow_spawn_egg.png","creaking_spawn_egg.png","creeper_banner_pattern.png","creeper_spawn_egg.png","crimson_door.png","crimson_hanging_sign.png","crimson_sign.png","crossbow_arrow.png","crossbow_firework.png","crossbow_pulling_0.png","crossbow_pulling_1.png","crossbow_pulling_2.png","crossbow_standby.png","cyan_bundle.png","cyan_bundle_open_back.png","cyan_bundle_open_front.png","cyan_candle.png","cyan_dye.png","cyan_harness.png","danger_pottery_sherd.png","dark_oak_boat.png","dark_oak_chest_boat.png","dark_oak_door.png","dark_oak_hanging_sign.png","dark_oak_sign.png","diamond.png","diamond_axe.png","diamond_boots.png","diamond_chestplate.png","diamond_helmet.png","diamond_hoe.png","diamond_horse_armor.png","diamond_leggings.png","diamond_pickaxe.png","diamond_shovel.png","diamond_sword.png","disc_fragment_5.png","dolphin_spawn_egg.png","donkey_spawn_egg.png","dragon_breath.png","dried_kelp.png","drowned_spawn_egg.png","dune_armor_trim_smithing_template.png","echo_shard.png","egg.png","elder_guardian_spawn_egg.png","elytra.png","elytra_broken.png","emerald.png","enchanted_book.png","end_crystal.png","ender_dragon_spawn_egg.png","ender_eye.png","ender_pearl.png","enderman_spawn_egg.png","endermite_spawn_egg.png","evoker_spawn_egg.png","experience_bottle.png","explorer_pottery_sherd.png","exposed_copper_door.png","eye_armor_trim_smithing_template.png","feather.png","fermented_spider_eye.png","field_masoned_banner_pattern.png","filled_map.png","filled_map_markings.png","fire_charge.png","firefly_bush.png","firework_rocket.png","firework_star.png","firework_star_overlay.png","fishing_rod.png","fishing_rod_cast.png","flint.png","flint_and_steel.png","flow_armor_trim_smithing_template.png","flow_banner_pattern.png","flow_pottery_sherd.png","flower_banner_pattern.png","flower_pot.png","fox_spawn_egg.png","friend_pottery_sherd.png","frog_spawn_egg.png","furnace_minecart.png","ghast_spawn_egg.png","ghast_tear.png","glass_bottle.png","glistering_melon_slice.png","globe_banner_pattern.png","glow_berries.png","glow_ink_sac.png","glow_item_frame.png","glow_squid_spawn_egg.png","glowstone_dust.png","goat_horn.png","goat_spawn_egg.png","gold_ingot.png","gold_nugget.png","golden_apple.png","golden_axe.png","golden_boots.png","golden_carrot.png","golden_chestplate.png","golden_helmet.png","golden_hoe.png","golden_horse_armor.png","golden_leggings.png","golden_pickaxe.png","golden_shovel.png","golden_sword.png","gray_bundle.png","gray_bundle_open_back.png","gray_bundle_open_front.png","gray_candle.png","gray_dye.png","gray_harness.png","green_bundle.png","green_bundle_open_back.png","green_bundle_open_front.png","green_candle.png","green_dye.png","green_harness.png","guardian_spawn_egg.png","gunpowder.png","guster_banner_pattern.png","guster_pottery_sherd.png","happy_ghast_spawn_egg.png","heart_of_the_sea.png","heart_pottery_sherd.png","heartbreak_pottery_sherd.png","hoglin_spawn_egg.png","honey_bottle.png","honeycomb.png","hopper.png","hopper_minecart.png","horse_spawn_egg.png","host_armor_trim_smithing_template.png","howl_pottery_sherd.png","husk_spawn_egg.png","ink_sac.png","iron_axe.png","iron_boots.png","iron_chestplate.png","iron_door.png","iron_golem_spawn_egg.png","iron_helmet.png","iron_hoe.png","iron_horse_armor.png","iron_ingot.png","iron_leggings.png","iron_nugget.png","iron_pickaxe.png","iron_shovel.png","iron_sword.png","item_frame.png","jungle_boat.png","jungle_chest_boat.png","jungle_door.png","jungle_hanging_sign.png","jungle_sign.png","kelp.png","knowledge_book.png","lantern.png","lapis_lazuli.png","lava_bucket.png","lead.png","leaf_litter.png","leather.png","leather_boots.png","leather_boots_overlay.png","leather_chestplate.png","leather_chestplate_overlay.png","leather_helmet.png","leather_helmet_overlay.png","leather_horse_armor.png","leather_leggings.png","leather_leggings_overlay.png","light.png","light_00.png","light_01.png","light_02.png","light_03.png","light_04.png","light_05.png","light_06.png","light_07.png","light_08.png","light_09.png","light_10.png","light_11.png","light_12.png","light_13.png","light_14.png","light_15.png","light_blue_bundle.png","light_blue_bundle_open_back.png","light_blue_bundle_open_front.png","light_blue_candle.png","light_blue_dye.png","light_blue_harness.png","light_gray_bundle.png","light_gray_bundle_open_back.png","light_gray_bundle_open_front.png","light_gray_candle.png","light_gray_dye.png","light_gray_harness.png","lime_bundle.png","lime_bundle_open_back.png","lime_bundle_open_front.png","lime_candle.png","lime_dye.png","lime_harness.png","lingering_potion.png","llama_spawn_egg.png","mace.png","magenta_bundle.png","magenta_bundle_open_back.png","magenta_bundle_open_front.png","magenta_candle.png","magenta_dye.png","magenta_harness.png","magma_cream.png","magma_cube_spawn_egg.png","mangrove_boat.png","mangrove_chest_boat.png","mangrove_door.png","mangrove_hanging_sign.png","mangrove_propagule.png","mangrove_sign.png","map.png","melon_seeds.png","melon_slice.png","milk_bucket.png","minecart.png","miner_pottery_sherd.png","mojang_banner_pattern.png","mooshroom_spawn_egg.png","mourner_pottery_sherd.png","mule_spawn_egg.png","mushroom_stew.png","music_disc_11.png","music_disc_13.png","music_disc_5.png","music_disc_blocks.png","music_disc_cat.png","music_disc_chirp.png","music_disc_creator.png","music_disc_creator_music_box.png","music_disc_far.png","music_disc_mall.png","music_disc_mellohi.png","music_disc_otherside.png","music_disc_pigstep.png","music_disc_precipice.png","music_disc_relic.png","music_disc_stal.png","music_disc_strad.png","music_disc_tears.png","music_disc_wait.png","music_disc_ward.png","mutton.png","name_tag.png","nautilus_shell.png","nether_brick.png","nether_sprouts.png","nether_star.png","nether_wart.png","netherite_axe.png","netherite_boots.png","netherite_chestplate.png","netherite_helmet.png","netherite_hoe.png","netherite_ingot.png","netherite_leggings.png","netherite_pickaxe.png","netherite_scrap.png","netherite_shovel.png","netherite_sword.png","netherite_upgrade_smithing_template.png","oak_boat.png","oak_chest_boat.png","oak_door.png","oak_hanging_sign.png","oak_sign.png","ocelot_spawn_egg.png","ominous_bottle.png","ominous_trial_key.png","orange_bundle.png","orange_bundle_open_back.png","orange_bundle_open_front.png","orange_candle.png","orange_dye.png","orange_harness.png","oxidized_copper_door.png","painting.png","pale_oak_boat.png","pale_oak_chest_boat.png","pale_oak_door.png","pale_oak_hanging_sign.png","pale_oak_sign.png","panda_spawn_egg.png","paper.png","parrot_spawn_egg.png","phantom_membrane.png","phantom_spawn_egg.png","pig_spawn_egg.png","piglin_banner_pattern.png","piglin_brute_spawn_egg.png","piglin_spawn_egg.png","pillager_spawn_egg.png","pink_bundle.png","pink_bundle_open_back.png","pink_bundle_open_front.png","pink_candle.png","pink_dye.png","pink_harness.png","pink_petals.png","pitcher_plant.png","pitcher_pod.png","plenty_pottery_sherd.png","pointed_dripstone.png","poisonous_potato.png","polar_bear_spawn_egg.png","popped_chorus_fruit.png","porkchop.png","potato.png","potion.png","potion_overlay.png","powder_snow_bucket.png","prismarine_crystals.png","prismarine_shard.png","prize_pottery_sherd.png","pufferfish.png","pufferfish_bucket.png","pufferfish_spawn_egg.png","pumpkin_pie.png","pumpkin_seeds.png","purple_bundle.png","purple_bundle_open_back.png","purple_bundle_open_front.png","purple_candle.png","purple_dye.png","purple_harness.png","quartz.png","rabbit.png","rabbit_foot.png","rabbit_hide.png","rabbit_spawn_egg.png","rabbit_stew.png","raiser_armor_trim_smithing_template.png","ravager_spawn_egg.png","raw_copper.png","raw_gold.png","raw_iron.png","recovery_compass_00.png","recovery_compass_01.png","recovery_compass_02.png","recovery_compass_03.png","recovery_compass_04.png","recovery_compass_05.png","recovery_compass_06.png","recovery_compass_07.png","recovery_compass_08.png","recovery_compass_09.png","recovery_compass_10.png","recovery_compass_11.png","recovery_compass_12.png","recovery_compass_13.png","recovery_compass_14.png","recovery_compass_15.png","recovery_compass_16.png","recovery_compass_17.png","recovery_compass_18.png","recovery_compass_19.png","recovery_compass_20.png","recovery_compass_21.png","recovery_compass_22.png","recovery_compass_23.png","recovery_compass_24.png","recovery_compass_25.png","recovery_compass_26.png","recovery_compass_27.png","recovery_compass_28.png","recovery_compass_29.png","recovery_compass_30.png","recovery_compass_31.png","red_bundle.png","red_bundle_open_back.png","red_bundle_open_front.png","red_candle.png","red_dye.png","red_harness.png","redstone.png","repeater.png","resin_brick.png","resin_clump.png","rib_armor_trim_smithing_template.png","rotten_flesh.png","saddle.png","salmon.png","salmon_bucket.png","salmon_spawn_egg.png","scrape_pottery_sherd.png","sea_pickle.png","seagrass.png","sentry_armor_trim_smithing_template.png","shaper_armor_trim_smithing_template.png","sheaf_pottery_sherd.png","shears.png","sheep_spawn_egg.png","shelter_pottery_sherd.png","shulker_shell.png","shulker_spawn_egg.png","silence_armor_trim_smithing_template.png","silverfish_spawn_egg.png","skeleton_horse_spawn_egg.png","skeleton_spawn_egg.png","skull_banner_pattern.png","skull_pottery_sherd.png","slime_ball.png","slime_spawn_egg.png","sniffer_egg.png","sniffer_spawn_egg.png","snort_pottery_sherd.png","snout_armor_trim_smithing_template.png","snow_golem_spawn_egg.png","snowball.png","soul_campfire.png","soul_lantern.png","spectral_arrow.png","spider_eye.png","spider_spawn_egg.png","spire_armor_trim_smithing_template.png","splash_potion.png","spruce_boat.png","spruce_chest_boat.png","spruce_door.png","spruce_hanging_sign.png","spruce_sign.png","spyglass.png","spyglass_model.png","squid_spawn_egg.png","stick.png","stone_axe.png","stone_hoe.png","stone_pickaxe.png","stone_shovel.png","stone_sword.png","stray_spawn_egg.png","strider_spawn_egg.png","string.png","structure_void.png","sugar.png","sugar_cane.png","suspicious_stew.png","sweet_berries.png","tadpole_bucket.png","tadpole_spawn_egg.png","tide_armor_trim_smithing_template.png","tipped_arrow_base.png","tipped_arrow_head.png","tnt_minecart.png","torchflower_seeds.png","totem_of_undying.png","trader_llama_spawn_egg.png","trial_key.png","trident.png","tropical_fish.png","tropical_fish_bucket.png","tropical_fish_spawn_egg.png","turtle_egg.png","turtle_helmet.png","turtle_scute.png","turtle_spawn_egg.png","vex_armor_trim_smithing_template.png","vex_spawn_egg.png","villager_spawn_egg.png","vindicator_spawn_egg.png","wandering_trader_spawn_egg.png","ward_armor_trim_smithing_template.png","warden_spawn_egg.png","warped_door.png","warped_fungus_on_a_stick.png","warped_hanging_sign.png","warped_sign.png","water_bucket.png","wayfinder_armor_trim_smithing_template.png","weathered_copper_door.png","wheat.png","wheat_seeds.png","white_bundle.png","white_bundle_open_back.png","white_bundle_open_front.png","white_candle.png","white_dye.png","white_harness.png","wild_armor_trim_smithing_template.png","wildflowers.png","wind_charge.png","witch_spawn_egg.png","wither_skeleton_spawn_egg.png","wither_spawn_egg.png","wolf_armor.png","wolf_armor_overlay.png","wolf_spawn_egg.png","wooden_axe.png","wooden_hoe.png","wooden_pickaxe.png","wooden_shovel.png","wooden_sword.png","writable_book.png","written_book.png","yellow_bundle.png","yellow_bundle_open_back.png","yellow_bundle_open_front.png","yellow_candle.png","yellow_dye.png","yellow_harness.png","zoglin_spawn_egg.png","zombie_horse_spawn_egg.png","zombie_spawn_egg.png","zombie_villager_spawn_egg.png","zombified_piglin_spawn_egg.png"]} \ No newline at end of file +{"directories":[],"files":["acacia_boat.png","acacia_chest_boat.png","acacia_door.png","acacia_hanging_sign.png","acacia_sign.png","allay_spawn_egg.png","amethyst_shard.png","angler_pottery_sherd.png","apple.png","archer_pottery_sherd.png","armadillo_scute.png","armadillo_spawn_egg.png","armor_stand.png","arms_up_pottery_sherd.png","arrow.png","axolotl_bucket.png","axolotl_spawn_egg.png","baked_potato.png","bamboo.png","bamboo_chest_raft.png","bamboo_door.png","bamboo_hanging_sign.png","bamboo_raft.png","bamboo_sign.png","barrier.png","bat_spawn_egg.png","bee_spawn_egg.png","beef.png","beetroot.png","beetroot_seeds.png","beetroot_soup.png","bell.png","birch_boat.png","birch_chest_boat.png","birch_door.png","birch_hanging_sign.png","birch_sign.png","black_bundle.png","black_bundle_open_back.png","black_bundle_open_front.png","black_candle.png","black_dye.png","black_harness.png","blade_pottery_sherd.png","blaze_powder.png","blaze_rod.png","blaze_spawn_egg.png","blue_bundle.png","blue_bundle_open_back.png","blue_bundle_open_front.png","blue_candle.png","blue_dye.png","blue_egg.png","blue_harness.png","bogged_spawn_egg.png","bolt_armor_trim_smithing_template.png","bone.png","bone_meal.png","book.png","bordure_indented_banner_pattern.png","bow.png","bow_pulling_0.png","bow_pulling_1.png","bow_pulling_2.png","bowl.png","bread.png","breeze_rod.png","breeze_spawn_egg.png","brewer_pottery_sherd.png","brewing_stand.png","brick.png","brown_bundle.png","brown_bundle_open_back.png","brown_bundle_open_front.png","brown_candle.png","brown_dye.png","brown_egg.png","brown_harness.png","brush.png","bucket.png","bundle.png","bundle_open_back.png","bundle_open_front.png","burn_pottery_sherd.png","cake.png","camel_spawn_egg.png","campfire.png","candle.png","carrot.png","carrot_on_a_stick.png","cat_spawn_egg.png","cauldron.png","cave_spider_spawn_egg.png","chain.png","chainmail_boots.png","chainmail_chestplate.png","chainmail_helmet.png","chainmail_leggings.png","charcoal.png","cherry_boat.png","cherry_chest_boat.png","cherry_door.png","cherry_hanging_sign.png","cherry_sign.png","chest_minecart.png","chicken.png","chicken_spawn_egg.png","chorus_fruit.png","clay_ball.png","clock_00.png","clock_01.png","clock_02.png","clock_03.png","clock_04.png","clock_05.png","clock_06.png","clock_07.png","clock_08.png","clock_09.png","clock_10.png","clock_11.png","clock_12.png","clock_13.png","clock_14.png","clock_15.png","clock_16.png","clock_17.png","clock_18.png","clock_19.png","clock_20.png","clock_21.png","clock_22.png","clock_23.png","clock_24.png","clock_25.png","clock_26.png","clock_27.png","clock_28.png","clock_29.png","clock_30.png","clock_31.png","clock_32.png","clock_33.png","clock_34.png","clock_35.png","clock_36.png","clock_37.png","clock_38.png","clock_39.png","clock_40.png","clock_41.png","clock_42.png","clock_43.png","clock_44.png","clock_45.png","clock_46.png","clock_47.png","clock_48.png","clock_49.png","clock_50.png","clock_51.png","clock_52.png","clock_53.png","clock_54.png","clock_55.png","clock_56.png","clock_57.png","clock_58.png","clock_59.png","clock_60.png","clock_61.png","clock_62.png","clock_63.png","coal.png","coast_armor_trim_smithing_template.png","cocoa_beans.png","cod.png","cod_bucket.png","cod_spawn_egg.png","command_block_minecart.png","comparator.png","compass_00.png","compass_01.png","compass_02.png","compass_03.png","compass_04.png","compass_05.png","compass_06.png","compass_07.png","compass_08.png","compass_09.png","compass_10.png","compass_11.png","compass_12.png","compass_13.png","compass_14.png","compass_15.png","compass_16.png","compass_17.png","compass_18.png","compass_19.png","compass_20.png","compass_21.png","compass_22.png","compass_23.png","compass_24.png","compass_25.png","compass_26.png","compass_27.png","compass_28.png","compass_29.png","compass_30.png","compass_31.png","cooked_beef.png","cooked_chicken.png","cooked_cod.png","cooked_mutton.png","cooked_porkchop.png","cooked_rabbit.png","cooked_salmon.png","cookie.png","copper_door.png","copper_ingot.png","cow_spawn_egg.png","creaking_spawn_egg.png","creeper_banner_pattern.png","creeper_spawn_egg.png","crimson_door.png","crimson_hanging_sign.png","crimson_sign.png","crossbow_arrow.png","crossbow_firework.png","crossbow_pulling_0.png","crossbow_pulling_1.png","crossbow_pulling_2.png","crossbow_standby.png","cyan_bundle.png","cyan_bundle_open_back.png","cyan_bundle_open_front.png","cyan_candle.png","cyan_dye.png","cyan_harness.png","danger_pottery_sherd.png","dark_oak_boat.png","dark_oak_chest_boat.png","dark_oak_door.png","dark_oak_hanging_sign.png","dark_oak_sign.png","diamond.png","diamond_axe.png","diamond_boots.png","diamond_chestplate.png","diamond_helmet.png","diamond_hoe.png","diamond_horse_armor.png","diamond_leggings.png","diamond_pickaxe.png","diamond_shovel.png","diamond_sword.png","disc_fragment_5.png","dolphin_spawn_egg.png","donkey_spawn_egg.png","dragon_breath.png","dried_kelp.png","drowned_spawn_egg.png","dune_armor_trim_smithing_template.png","echo_shard.png","egg.png","elder_guardian_spawn_egg.png","elytra.png","elytra_broken.png","emerald.png","enchanted_book.png","end_crystal.png","ender_dragon_spawn_egg.png","ender_eye.png","ender_pearl.png","enderman_spawn_egg.png","endermite_spawn_egg.png","evoker_spawn_egg.png","experience_bottle.png","explorer_pottery_sherd.png","exposed_copper_door.png","eye_armor_trim_smithing_template.png","feather.png","fermented_spider_eye.png","field_masoned_banner_pattern.png","filled_map.png","filled_map_markings.png","fire_charge.png","firefly_bush.png","firework_rocket.png","firework_star.png","firework_star_overlay.png","fishing_rod.png","fishing_rod_cast.png","flint.png","flint_and_steel.png","flow_armor_trim_smithing_template.png","flow_banner_pattern.png","flow_pottery_sherd.png","flower_banner_pattern.png","flower_pot.png","fox_spawn_egg.png","friend_pottery_sherd.png","frog_spawn_egg.png","furnace_minecart.png","ghast_spawn_egg.png","ghast_tear.png","glass_bottle.png","glistering_melon_slice.png","globe_banner_pattern.png","glow_berries.png","glow_ink_sac.png","glow_item_frame.png","glow_squid_spawn_egg.png","glowstone_dust.png","goat_horn.png","goat_spawn_egg.png","gold_ingot.png","gold_nugget.png","golden_apple.png","golden_axe.png","golden_boots.png","golden_carrot.png","golden_chestplate.png","golden_helmet.png","golden_hoe.png","golden_horse_armor.png","golden_leggings.png","golden_pickaxe.png","golden_shovel.png","golden_sword.png","gray_bundle.png","gray_bundle_open_back.png","gray_bundle_open_front.png","gray_candle.png","gray_dye.png","gray_harness.png","green_bundle.png","green_bundle_open_back.png","green_bundle_open_front.png","green_candle.png","green_dye.png","green_harness.png","guardian_spawn_egg.png","gunpowder.png","guster_banner_pattern.png","guster_pottery_sherd.png","happy_ghast_spawn_egg.png","heart_of_the_sea.png","heart_pottery_sherd.png","heartbreak_pottery_sherd.png","hoglin_spawn_egg.png","honey_bottle.png","honeycomb.png","hopper.png","hopper_minecart.png","horse_spawn_egg.png","host_armor_trim_smithing_template.png","howl_pottery_sherd.png","husk_spawn_egg.png","ink_sac.png","iron_axe.png","iron_boots.png","iron_chestplate.png","iron_door.png","iron_golem_spawn_egg.png","iron_helmet.png","iron_hoe.png","iron_horse_armor.png","iron_ingot.png","iron_leggings.png","iron_nugget.png","iron_pickaxe.png","iron_shovel.png","iron_sword.png","item_frame.png","jungle_boat.png","jungle_chest_boat.png","jungle_door.png","jungle_hanging_sign.png","jungle_sign.png","kelp.png","knowledge_book.png","lantern.png","lapis_lazuli.png","lava_bucket.png","lead.png","leaf_litter.png","leather.png","leather_boots.png","leather_boots_overlay.png","leather_chestplate.png","leather_chestplate_overlay.png","leather_helmet.png","leather_helmet_overlay.png","leather_horse_armor.png","leather_leggings.png","leather_leggings_overlay.png","light.png","light_00.png","light_01.png","light_02.png","light_03.png","light_04.png","light_05.png","light_06.png","light_07.png","light_08.png","light_09.png","light_10.png","light_11.png","light_12.png","light_13.png","light_14.png","light_15.png","light_blue_bundle.png","light_blue_bundle_open_back.png","light_blue_bundle_open_front.png","light_blue_candle.png","light_blue_dye.png","light_blue_harness.png","light_gray_bundle.png","light_gray_bundle_open_back.png","light_gray_bundle_open_front.png","light_gray_candle.png","light_gray_dye.png","light_gray_harness.png","lime_bundle.png","lime_bundle_open_back.png","lime_bundle_open_front.png","lime_candle.png","lime_dye.png","lime_harness.png","lingering_potion.png","llama_spawn_egg.png","mace.png","magenta_bundle.png","magenta_bundle_open_back.png","magenta_bundle_open_front.png","magenta_candle.png","magenta_dye.png","magenta_harness.png","magma_cream.png","magma_cube_spawn_egg.png","mangrove_boat.png","mangrove_chest_boat.png","mangrove_door.png","mangrove_hanging_sign.png","mangrove_propagule.png","mangrove_sign.png","map.png","melon_seeds.png","melon_slice.png","milk_bucket.png","minecart.png","miner_pottery_sherd.png","mojang_banner_pattern.png","mooshroom_spawn_egg.png","mourner_pottery_sherd.png","mule_spawn_egg.png","mushroom_stew.png","music_disc_11.png","music_disc_13.png","music_disc_5.png","music_disc_blocks.png","music_disc_cat.png","music_disc_chirp.png","music_disc_creator.png","music_disc_creator_music_box.png","music_disc_far.png","music_disc_lava_chicken.png","music_disc_mall.png","music_disc_mellohi.png","music_disc_otherside.png","music_disc_pigstep.png","music_disc_precipice.png","music_disc_relic.png","music_disc_stal.png","music_disc_strad.png","music_disc_tears.png","music_disc_wait.png","music_disc_ward.png","mutton.png","name_tag.png","nautilus_shell.png","nether_brick.png","nether_sprouts.png","nether_star.png","nether_wart.png","netherite_axe.png","netherite_boots.png","netherite_chestplate.png","netherite_helmet.png","netherite_hoe.png","netherite_ingot.png","netherite_leggings.png","netherite_pickaxe.png","netherite_scrap.png","netherite_shovel.png","netherite_sword.png","netherite_upgrade_smithing_template.png","oak_boat.png","oak_chest_boat.png","oak_door.png","oak_hanging_sign.png","oak_sign.png","ocelot_spawn_egg.png","ominous_bottle.png","ominous_trial_key.png","orange_bundle.png","orange_bundle_open_back.png","orange_bundle_open_front.png","orange_candle.png","orange_dye.png","orange_harness.png","oxidized_copper_door.png","painting.png","pale_oak_boat.png","pale_oak_chest_boat.png","pale_oak_door.png","pale_oak_hanging_sign.png","pale_oak_sign.png","panda_spawn_egg.png","paper.png","parrot_spawn_egg.png","phantom_membrane.png","phantom_spawn_egg.png","pig_spawn_egg.png","piglin_banner_pattern.png","piglin_brute_spawn_egg.png","piglin_spawn_egg.png","pillager_spawn_egg.png","pink_bundle.png","pink_bundle_open_back.png","pink_bundle_open_front.png","pink_candle.png","pink_dye.png","pink_harness.png","pink_petals.png","pitcher_plant.png","pitcher_pod.png","plenty_pottery_sherd.png","pointed_dripstone.png","poisonous_potato.png","polar_bear_spawn_egg.png","popped_chorus_fruit.png","porkchop.png","potato.png","potion.png","potion_overlay.png","powder_snow_bucket.png","prismarine_crystals.png","prismarine_shard.png","prize_pottery_sherd.png","pufferfish.png","pufferfish_bucket.png","pufferfish_spawn_egg.png","pumpkin_pie.png","pumpkin_seeds.png","purple_bundle.png","purple_bundle_open_back.png","purple_bundle_open_front.png","purple_candle.png","purple_dye.png","purple_harness.png","quartz.png","rabbit.png","rabbit_foot.png","rabbit_hide.png","rabbit_spawn_egg.png","rabbit_stew.png","raiser_armor_trim_smithing_template.png","ravager_spawn_egg.png","raw_copper.png","raw_gold.png","raw_iron.png","recovery_compass_00.png","recovery_compass_01.png","recovery_compass_02.png","recovery_compass_03.png","recovery_compass_04.png","recovery_compass_05.png","recovery_compass_06.png","recovery_compass_07.png","recovery_compass_08.png","recovery_compass_09.png","recovery_compass_10.png","recovery_compass_11.png","recovery_compass_12.png","recovery_compass_13.png","recovery_compass_14.png","recovery_compass_15.png","recovery_compass_16.png","recovery_compass_17.png","recovery_compass_18.png","recovery_compass_19.png","recovery_compass_20.png","recovery_compass_21.png","recovery_compass_22.png","recovery_compass_23.png","recovery_compass_24.png","recovery_compass_25.png","recovery_compass_26.png","recovery_compass_27.png","recovery_compass_28.png","recovery_compass_29.png","recovery_compass_30.png","recovery_compass_31.png","red_bundle.png","red_bundle_open_back.png","red_bundle_open_front.png","red_candle.png","red_dye.png","red_harness.png","redstone.png","repeater.png","resin_brick.png","resin_clump.png","rib_armor_trim_smithing_template.png","rotten_flesh.png","saddle.png","salmon.png","salmon_bucket.png","salmon_spawn_egg.png","scrape_pottery_sherd.png","sea_pickle.png","seagrass.png","sentry_armor_trim_smithing_template.png","shaper_armor_trim_smithing_template.png","sheaf_pottery_sherd.png","shears.png","sheep_spawn_egg.png","shelter_pottery_sherd.png","shulker_shell.png","shulker_spawn_egg.png","silence_armor_trim_smithing_template.png","silverfish_spawn_egg.png","skeleton_horse_spawn_egg.png","skeleton_spawn_egg.png","skull_banner_pattern.png","skull_pottery_sherd.png","slime_ball.png","slime_spawn_egg.png","sniffer_egg.png","sniffer_spawn_egg.png","snort_pottery_sherd.png","snout_armor_trim_smithing_template.png","snow_golem_spawn_egg.png","snowball.png","soul_campfire.png","soul_lantern.png","spectral_arrow.png","spider_eye.png","spider_spawn_egg.png","spire_armor_trim_smithing_template.png","splash_potion.png","spruce_boat.png","spruce_chest_boat.png","spruce_door.png","spruce_hanging_sign.png","spruce_sign.png","spyglass.png","spyglass_model.png","squid_spawn_egg.png","stick.png","stone_axe.png","stone_hoe.png","stone_pickaxe.png","stone_shovel.png","stone_sword.png","stray_spawn_egg.png","strider_spawn_egg.png","string.png","structure_void.png","sugar.png","sugar_cane.png","suspicious_stew.png","sweet_berries.png","tadpole_bucket.png","tadpole_spawn_egg.png","tide_armor_trim_smithing_template.png","tipped_arrow_base.png","tipped_arrow_head.png","tnt_minecart.png","torchflower_seeds.png","totem_of_undying.png","trader_llama_spawn_egg.png","trial_key.png","trident.png","tropical_fish.png","tropical_fish_bucket.png","tropical_fish_spawn_egg.png","turtle_egg.png","turtle_helmet.png","turtle_scute.png","turtle_spawn_egg.png","vex_armor_trim_smithing_template.png","vex_spawn_egg.png","villager_spawn_egg.png","vindicator_spawn_egg.png","wandering_trader_spawn_egg.png","ward_armor_trim_smithing_template.png","warden_spawn_egg.png","warped_door.png","warped_fungus_on_a_stick.png","warped_hanging_sign.png","warped_sign.png","water_bucket.png","wayfinder_armor_trim_smithing_template.png","weathered_copper_door.png","wheat.png","wheat_seeds.png","white_bundle.png","white_bundle_open_back.png","white_bundle_open_front.png","white_candle.png","white_dye.png","white_harness.png","wild_armor_trim_smithing_template.png","wildflowers.png","wind_charge.png","witch_spawn_egg.png","wither_skeleton_spawn_egg.png","wither_spawn_egg.png","wolf_armor.png","wolf_armor_overlay.png","wolf_spawn_egg.png","wooden_axe.png","wooden_hoe.png","wooden_pickaxe.png","wooden_shovel.png","wooden_sword.png","writable_book.png","written_book.png","yellow_bundle.png","yellow_bundle_open_back.png","yellow_bundle_open_front.png","yellow_candle.png","yellow_dye.png","yellow_harness.png","zoglin_spawn_egg.png","zombie_horse_spawn_egg.png","zombie_spawn_egg.png","zombie_villager_spawn_egg.png","zombified_piglin_spawn_egg.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/map/_list.json b/common-files/src/main/resources/internal/textures/map/_list.json new file mode 100644 index 000000000..ba655cf14 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/map/_list.json @@ -0,0 +1 @@ +{"directories":["decorations"],"files":["map_background.png","map_background_checkerboard.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/map/decorations/_list.json b/common-files/src/main/resources/internal/textures/map/decorations/_list.json new file mode 100644 index 000000000..8482cc88f --- /dev/null +++ b/common-files/src/main/resources/internal/textures/map/decorations/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["black_banner.png","blue_banner.png","blue_marker.png","brown_banner.png","cyan_banner.png","desert_village.png","frame.png","gray_banner.png","green_banner.png","jungle_temple.png","light_blue_banner.png","light_gray_banner.png","lime_banner.png","magenta_banner.png","ocean_monument.png","orange_banner.png","pink_banner.png","plains_village.png","player.png","player_off_limits.png","player_off_map.png","purple_banner.png","red_banner.png","red_marker.png","red_x.png","savanna_village.png","snowy_village.png","swamp_hut.png","taiga_village.png","target_point.png","target_x.png","trial_chambers.png","white_banner.png","woodland_mansion.png","yellow_banner.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/misc/_list.json b/common-files/src/main/resources/internal/textures/misc/_list.json new file mode 100644 index 000000000..5e62d577f --- /dev/null +++ b/common-files/src/main/resources/internal/textures/misc/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["credits_vignette.png","credits_vignette.png.mcmeta","enchanted_glint_armor.png","enchanted_glint_armor.png.mcmeta","enchanted_glint_item.png","enchanted_glint_item.png.mcmeta","forcefield.png","nausea.png","nausea.png.mcmeta","powder_snow_outline.png","pumpkinblur.png","pumpkinblur.png.mcmeta","shadow.png","shadow.png.mcmeta","spyglass_scope.png","underwater.png","unknown_pack.png","unknown_server.png","vignette.png","vignette.png.mcmeta","white.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/mob_effect/_list.json b/common-files/src/main/resources/internal/textures/mob_effect/_list.json new file mode 100644 index 000000000..351bdea95 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/mob_effect/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["absorption.png","bad_omen.png","blindness.png","conduit_power.png","darkness.png","dolphins_grace.png","fire_resistance.png","glowing.png","haste.png","health_boost.png","hero_of_the_village.png","hunger.png","infested.png","instant_damage.png","instant_health.png","invisibility.png","jump_boost.png","levitation.png","luck.png","mining_fatigue.png","nausea.png","night_vision.png","oozing.png","poison.png","raid_omen.png","regeneration.png","resistance.png","saturation.png","slow_falling.png","slowness.png","speed.png","strength.png","trial_omen.png","unluck.png","water_breathing.png","weakness.png","weaving.png","wind_charged.png","wither.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/painting/_list.json b/common-files/src/main/resources/internal/textures/painting/_list.json new file mode 100644 index 000000000..ae4993796 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/painting/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["alban.png","aztec.png","aztec2.png","back.png","backyard.png","baroque.png","bomb.png","bouquet.png","burning_skull.png","bust.png","cavebird.png","changing.png","cotan.png","courbet.png","creebet.png","dennis.png","donkey_kong.png","earth.png","endboss.png","fern.png","fighters.png","finding.png","fire.png","graham.png","humble.png","kebab.png","lowmist.png","match.png","meditative.png","orb.png","owlemons.png","passage.png","pigscene.png","plant.png","pointer.png","pond.png","pool.png","prairie_ride.png","sea.png","skeleton.png","skull_and_roses.png","stage.png","sunflowers.png","sunset.png","tides.png","unpacked.png","void.png","wanderer.png","wasteland.png","water.png","wind.png","wither.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/particle/_list.json b/common-files/src/main/resources/internal/textures/particle/_list.json new file mode 100644 index 000000000..5dd5db100 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/particle/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["angry.png","big_smoke_0.png","big_smoke_1.png","big_smoke_10.png","big_smoke_11.png","big_smoke_2.png","big_smoke_3.png","big_smoke_4.png","big_smoke_5.png","big_smoke_6.png","big_smoke_7.png","big_smoke_8.png","big_smoke_9.png","bubble.png","bubble_pop_0.png","bubble_pop_1.png","bubble_pop_2.png","bubble_pop_3.png","bubble_pop_4.png","cherry_0.png","cherry_1.png","cherry_10.png","cherry_11.png","cherry_2.png","cherry_3.png","cherry_4.png","cherry_5.png","cherry_6.png","cherry_7.png","cherry_8.png","cherry_9.png","critical_hit.png","damage.png","drip_fall.png","drip_hang.png","drip_land.png","effect_0.png","effect_1.png","effect_2.png","effect_3.png","effect_4.png","effect_5.png","effect_6.png","effect_7.png","enchanted_hit.png","explosion_0.png","explosion_1.png","explosion_10.png","explosion_11.png","explosion_12.png","explosion_13.png","explosion_14.png","explosion_15.png","explosion_2.png","explosion_3.png","explosion_4.png","explosion_5.png","explosion_6.png","explosion_7.png","explosion_8.png","explosion_9.png","firefly.png","flame.png","flash.png","generic_0.png","generic_1.png","generic_2.png","generic_3.png","generic_4.png","generic_5.png","generic_6.png","generic_7.png","glint.png","glitter_0.png","glitter_1.png","glitter_2.png","glitter_3.png","glitter_4.png","glitter_5.png","glitter_6.png","glitter_7.png","glow.png","goldheart_0.png","goldheart_1.png","goldheart_2.png","gust_0.png","gust_1.png","gust_10.png","gust_11.png","gust_2.png","gust_3.png","gust_4.png","gust_5.png","gust_6.png","gust_7.png","gust_8.png","gust_9.png","heart.png","infested.png","lava.png","leaf_0.png","leaf_1.png","leaf_10.png","leaf_11.png","leaf_2.png","leaf_3.png","leaf_4.png","leaf_5.png","leaf_6.png","leaf_7.png","leaf_8.png","leaf_9.png","nautilus.png","note.png","ominous_spawning.png","pale_oak_0.png","pale_oak_1.png","pale_oak_10.png","pale_oak_11.png","pale_oak_2.png","pale_oak_3.png","pale_oak_4.png","pale_oak_5.png","pale_oak_6.png","pale_oak_7.png","pale_oak_8.png","pale_oak_9.png","raid_omen.png","sculk_charge_0.png","sculk_charge_1.png","sculk_charge_2.png","sculk_charge_3.png","sculk_charge_4.png","sculk_charge_5.png","sculk_charge_6.png","sculk_charge_pop_0.png","sculk_charge_pop_1.png","sculk_charge_pop_2.png","sculk_charge_pop_3.png","sculk_soul_0.png","sculk_soul_1.png","sculk_soul_10.png","sculk_soul_2.png","sculk_soul_3.png","sculk_soul_4.png","sculk_soul_5.png","sculk_soul_6.png","sculk_soul_7.png","sculk_soul_8.png","sculk_soul_9.png","sga_a.png","sga_b.png","sga_c.png","sga_d.png","sga_e.png","sga_f.png","sga_g.png","sga_h.png","sga_i.png","sga_j.png","sga_k.png","sga_l.png","sga_m.png","sga_n.png","sga_o.png","sga_p.png","sga_q.png","sga_r.png","sga_s.png","sga_t.png","sga_u.png","sga_v.png","sga_w.png","sga_x.png","sga_y.png","sga_z.png","shriek.png","small_gust_0.png","small_gust_1.png","small_gust_2.png","small_gust_3.png","small_gust_4.png","small_gust_5.png","small_gust_6.png","sonic_boom_0.png","sonic_boom_1.png","sonic_boom_10.png","sonic_boom_11.png","sonic_boom_12.png","sonic_boom_13.png","sonic_boom_14.png","sonic_boom_15.png","sonic_boom_2.png","sonic_boom_3.png","sonic_boom_4.png","sonic_boom_5.png","sonic_boom_6.png","sonic_boom_7.png","sonic_boom_8.png","sonic_boom_9.png","soul_0.png","soul_1.png","soul_10.png","soul_2.png","soul_3.png","soul_4.png","soul_5.png","soul_6.png","soul_7.png","soul_8.png","soul_9.png","soul_fire_flame.png","spark_0.png","spark_1.png","spark_2.png","spark_3.png","spark_4.png","spark_5.png","spark_6.png","spark_7.png","spell_0.png","spell_1.png","spell_2.png","spell_3.png","spell_4.png","spell_5.png","spell_6.png","spell_7.png","splash_0.png","splash_1.png","splash_2.png","splash_3.png","sweep_0.png","sweep_1.png","sweep_2.png","sweep_3.png","sweep_4.png","sweep_5.png","sweep_6.png","sweep_7.png","trial_omen.png","trial_spawner_detection_0.png","trial_spawner_detection_1.png","trial_spawner_detection_2.png","trial_spawner_detection_3.png","trial_spawner_detection_4.png","trial_spawner_detection_ominous_0.png","trial_spawner_detection_ominous_1.png","trial_spawner_detection_ominous_2.png","trial_spawner_detection_ominous_3.png","trial_spawner_detection_ominous_4.png","vault_connection.png","vibration.png","vibration.png.mcmeta"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/trims/_list.json b/common-files/src/main/resources/internal/textures/trims/_list.json new file mode 100644 index 000000000..c69c06142 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/trims/_list.json @@ -0,0 +1 @@ +{"directories":["color_palettes","entity","items"],"files":[]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/trims/color_palettes/_list.json b/common-files/src/main/resources/internal/textures/trims/color_palettes/_list.json new file mode 100644 index 000000000..c4a5269d1 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/trims/color_palettes/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["amethyst.png","copper.png","diamond.png","diamond_darker.png","emerald.png","gold.png","gold_darker.png","iron.png","iron_darker.png","lapis.png","netherite.png","netherite_darker.png","quartz.png","redstone.png","resin.png","trim_palette.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/trims/entity/_list.json b/common-files/src/main/resources/internal/textures/trims/entity/_list.json new file mode 100644 index 000000000..8a6bf51b7 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/trims/entity/_list.json @@ -0,0 +1 @@ +{"directories":["humanoid","humanoid_leggings"],"files":[]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/trims/entity/humanoid/_list.json b/common-files/src/main/resources/internal/textures/trims/entity/humanoid/_list.json new file mode 100644 index 000000000..55d694706 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/trims/entity/humanoid/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["bolt.png","coast.png","dune.png","eye.png","flow.png","host.png","raiser.png","rib.png","sentry.png","shaper.png","silence.png","snout.png","spire.png","tide.png","vex.png","ward.png","wayfinder.png","wild.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/trims/entity/humanoid_leggings/_list.json b/common-files/src/main/resources/internal/textures/trims/entity/humanoid_leggings/_list.json new file mode 100644 index 000000000..55d694706 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/trims/entity/humanoid_leggings/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["bolt.png","coast.png","dune.png","eye.png","flow.png","host.png","raiser.png","rib.png","sentry.png","shaper.png","silence.png","snout.png","spire.png","tide.png","vex.png","ward.png","wayfinder.png","wild.png"]} \ No newline at end of file diff --git a/common-files/src/main/resources/internal/textures/trims/items/_list.json b/common-files/src/main/resources/internal/textures/trims/items/_list.json new file mode 100644 index 000000000..e5cf69a14 --- /dev/null +++ b/common-files/src/main/resources/internal/textures/trims/items/_list.json @@ -0,0 +1 @@ +{"directories":[],"files":["boots_trim.png","chestplate_trim.png","helmet_trim.png","leggings_trim.png"]} \ No newline at end of file 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 6018cc3c2..33bc98478 100644 --- a/common-files/src/main/resources/resources/default/configuration/items.yml +++ b/common-files/src/main/resources/resources/default/configuration/items.yml @@ -153,27 +153,6 @@ items#topaz_gears: template: default:model/simplified_handheld arguments: path: minecraft:item/custom/topaz_sword - $$>=1.21.2#armor: - default:topaz_helmet: - template: default:armor/topaz - arguments: - part: helmet - slot: head - default:topaz_chestplate: - template: default:armor/topaz - arguments: - part: chestplate - slot: chest - default:topaz_leggings: - template: default:armor/topaz - arguments: - part: leggings - slot: legs - default:topaz_boots: - template: default:armor/topaz - arguments: - part: boots - slot: feet $$>=1.21.4#topaz_trident: default:topaz_trident: material: trident @@ -288,6 +267,34 @@ items#topaz_gears: tints: - type: minecraft:dye default: -6265536 + default:topaz_helmet: + template: + - default:armor/topaz + arguments: + part: helmet + slot: head + material: topaz + default:topaz_chestplate: + template: + - default:armor/topaz + arguments: + part: chestplate + slot: chest + material: topaz + default:topaz_leggings: + template: + - default:armor/topaz + arguments: + part: leggings + slot: legs + material: topaz + default:topaz_boots: + template: + - default:armor/topaz + arguments: + part: boots + slot: feet + material: topaz templates: default:armor/topaz: material: chainmail_${part} @@ -298,122 +305,25 @@ templates: settings: tags: - default:topaz_tools - equippable: - slot: ${slot} - asset-id: topaz - humanoid: minecraft:topaz - humanoid-leggings: minecraft:topaz + - minecraft:trimmable_armor + equipment: + asset-id: default:topaz + $$>=1.21.2: + slot: ${slot} model: - type: minecraft:select - property: minecraft:trim_material - fallback: - type: minecraft:model - path: minecraft:item/custom/topaz_${part} - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/topaz_${part} - cases: - - when: minecraft:quartz - model: - type: minecraft:model - 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 - - when: minecraft:iron - model: - type: minecraft:model - 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 - - when: minecraft:netherite - model: - type: minecraft:model - 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 - - when: minecraft:redstone - model: - type: minecraft:model - 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 - - when: minecraft:copper - model: - type: minecraft:model - 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 - - when: minecraft:gold - model: - type: minecraft:model - 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 - - when: minecraft:emerald - model: - type: minecraft:model - 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 - - when: minecraft:diamond - model: - type: minecraft:model - 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 - - when: minecraft:lapis - model: - type: minecraft:model - 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 - - when: minecraft:amethyst - model: - type: minecraft:model - 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 - - when: minecraft:resin - model: - type: minecraft:model - 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 -recipes#topaz_gears: + template: default:model/armor_trim +equipments#topaz: + $$>=1.21.2: + default:topaz: + type: component + humanoid: minecraft:topaz + humanoid-leggings: minecraft:topaz + $$<1.21.2: + default:topaz: + type: trim + humanoid: minecraft:entity/equipment/humanoid/topaz + humanoid-leggings: minecraft:entity/equipment/humanoid_leggings/topaz +recipes#topaz: default:topaz_shovel: type: shaped pattern: @@ -474,49 +384,48 @@ recipes#topaz_gears: result: id: default:topaz_pickaxe count: 1 - $$>=1.21.2#armor: - default:topaz_helmet: - type: shaped - pattern: - - AAA - - A A - ingredients: - A: default:topaz - result: - id: default:topaz_helmet - count: 1 - default:topaz_chestplate: - type: shaped - pattern: - - A A - - AAA - - AAA - ingredients: - A: default:topaz - result: - id: default:topaz_chestplate - count: 1 - default:topaz_leggings: - type: shaped - pattern: - - AAA - - A A - - A A - ingredients: - A: default:topaz - result: - id: default:topaz_leggings - count: 1 - default:topaz_boots: - type: shaped - pattern: - - A A - - A A - ingredients: - A: default:topaz - result: - id: default:topaz_boots - count: 1 + default:topaz_helmet: + type: shaped + pattern: + - AAA + - A A + ingredients: + A: default:topaz + result: + id: default:topaz_helmet + count: 1 + default:topaz_chestplate: + type: shaped + pattern: + - A A + - AAA + - AAA + ingredients: + A: default:topaz + result: + id: default:topaz_chestplate + count: 1 + default:topaz_leggings: + type: shaped + pattern: + - AAA + - A A + - A A + ingredients: + A: default:topaz + result: + id: default:topaz_leggings + count: 1 + default:topaz_boots: + type: shaped + pattern: + - A A + - A A + ingredients: + A: default:topaz + result: + id: default:topaz_boots + count: 1 default:topaz_bow: type: smithing_transform base: minecraft:bow 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 57f5fd033..5760c9c18 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -1,22 +1,5 @@ # This file contains some useful template data. If you have good ideas, you are welcome to contribute your template! -# These templates let you ditch the real custom_model_data on the server side. -# Instead, we use client side components sent via packets to control how items look. -default:item/client_bound_custom_model_data: - custom-model-data: ${custom_model_data} - data: - remove-components: - - minecraft:custom_model_data - client-bound-data: - custom-model-data: ${custom_model_data} -default:item/client_bound_item_model: - item-model: ${item_model} - data: - remove-components: - - minecraft:item_model - client-bound-data: - item-model: ${item_model} - # blocks templates#models#block: # template: default:model/cube_all @@ -162,6 +145,120 @@ templates#models#2d: texture: ${path} broken_model: ${broken_path} broken_texture: ${broken_path} + # template: default:model/armor_trim + # arguments: + # material: armor material type + # part: slot type + default:model/armor_trim: + type: minecraft:select + property: minecraft:trim_material + fallback: + type: minecraft:model + path: minecraft:item/custom/${material}_${part} + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + cases: + - when: minecraft:quartz + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_quartz_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_quartz + - when: minecraft:iron + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_iron_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_iron + - when: minecraft:netherite + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_netherite_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_netherite + - when: minecraft:redstone + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_redstone_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_redstone + - when: minecraft:copper + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_copper_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_copper + - when: minecraft:gold + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_gold_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_gold + - when: minecraft:emerald + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_emerald_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_emerald + - when: minecraft:diamond + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_diamond_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_diamond + - when: minecraft:lapis + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_lapis_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_lapis + - when: minecraft:amethyst + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_amethyst_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_amethyst + - when: minecraft:resin + model: + type: minecraft:model + path: minecraft:item/custom/${material}_${part}_resin_trim + generation: + parent: minecraft:item/generated + textures: + layer0: minecraft:item/custom/${material}_${part} + layer1: minecraft:trims/items/${part}_trim_resin # shield templates#models#shield: @@ -2053,17 +2150,17 @@ templates#block_states: state: ${base_block}[type=top,waterlogged=false] model: path: ${model_top_path} - generation: ${model_top_generation} + generation: ${model_top_generation:-null} type=bottom,waterlogged=false: state: ${base_block}[type=bottom,waterlogged=false] model: path: ${model_bottom_path} - generation: ${model_bottom_generation} + generation: ${model_bottom_generation:-null} type=double,waterlogged=false: state: ${base_block}[type=double,waterlogged=false] model: path: ${model_double_path} - generation: ${model_double_generation} + generation: ${model_double_generation:-null} type=top,waterlogged=true: state: ${base_block}[type=top,waterlogged=true] model: diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_back.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_back.png new file mode 100644 index 000000000..bee2f3c2b Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_back.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_down.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_down.png new file mode 100644 index 000000000..51c403fbb Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_down.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_front.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_front.png new file mode 100644 index 000000000..56b8678bf Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_front.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_side.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_side.png new file mode 100644 index 000000000..4b2b7cffe Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_side.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_top.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_top.png new file mode 100644 index 000000000..a6c59abed Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/pickaxe_block_top.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_back.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_back.png new file mode 100644 index 000000000..f1ca41066 Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_back.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_down.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_down.png new file mode 100644 index 000000000..c220083d7 Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_down.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_front.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_front.png new file mode 100644 index 000000000..2f3f0070a Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_front.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_side.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_side.png new file mode 100644 index 000000000..ff94ffb51 Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_side.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_top.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_top.png new file mode 100644 index 000000000..43ec23e4f Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/place_block_top.png differ diff --git a/common-files/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/stonecutting_recipe.png b/common-files/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/stonecutting_recipe.png index 3ff743370..9cceec838 100644 Binary files a/common-files/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/stonecutting_recipe.png and b/common-files/src/main/resources/resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/stonecutting_recipe.png differ diff --git a/common-files/src/main/resources/resources/legacy_armor/configuration/chainmail.yml b/common-files/src/main/resources/resources/legacy_armor/configuration/chainmail.yml new file mode 100644 index 000000000..49d041fcf --- /dev/null +++ b/common-files/src/main/resources/resources/legacy_armor/configuration/chainmail.yml @@ -0,0 +1,30 @@ +# Since we removed the chainmail armor textures, we need to add a client-side trim type for the vanilla chainmail armor to make it display properly. +items: + minecraft:chainmail_helmet: + client-bound-data: + trim: + pattern: chainmail + material: custom + hide-tooltip: + - trim + minecraft:chainmail_chestplate: + client-bound-data: + trim: + pattern: chainmail + material: custom + hide-tooltip: + - trim + minecraft:chainmail_leggings: + client-bound-data: + trim: + pattern: chainmail + material: custom + hide-tooltip: + - trim + minecraft:chainmail_boots: + client-bound-data: + trim: + pattern: chainmail + material: custom + hide-tooltip: + - trim \ No newline at end of file diff --git a/common-files/src/main/resources/resources/legacy_armor/pack.yml b/common-files/src/main/resources/resources/legacy_armor/pack.yml new file mode 100644 index 000000000..f73b20dc9 --- /dev/null +++ b/common-files/src/main/resources/resources/legacy_armor/pack.yml @@ -0,0 +1,7 @@ +author: XiaoMoMi +version: 0.0.1 +description: Fix broken vanilla armor +namespace: minecraft +enable: + $$>=1.21.2: false + $$<1.21.2: true diff --git a/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid/chainmail.png b/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid/chainmail.png new file mode 100644 index 000000000..cd9ed23eb Binary files /dev/null and b/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid/chainmail.png differ diff --git a/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid_leggings/chainmail.png b/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid_leggings/chainmail.png new file mode 100644 index 000000000..0d47920d9 Binary files /dev/null and b/common-files/src/main/resources/resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid_leggings/chainmail.png differ diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index 2af081c0e..863854368 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -120,7 +120,8 @@ warning.config.image.invalid_hex_value: "Problem in Datei gefund warning.config.recipe.duplicate: "Problem in Datei gefunden - Dupliziertes Rezept ''. Bitte überprüfen Sie, ob dieselbe Konfiguration in anderen Dateien vorhanden ist." warning.config.recipe.missing_type: "Problem in Datei gefunden - Dem Rezept '' fehlt das erforderliche 'type'-Argument." warning.config.recipe.invalid_type: "Problem in Datei gefunden - Das Rezept '' verwendet einen ungültigen Rezepttyp ''." -warning.config.recipe.invalid_item: "Problem in Datei gefunden - Das Rezept '' verwendet einen ungültigen Gegenstand ''." +warning.config.recipe.invalid_ingredient: "Issue found in file - The recipe '' is using an invalid ingredient ''." +warning.config.recipe.invalid_result: "Issue found in file - The recipe '' is using an invalid result ''." warning.config.recipe.missing_ingredient: "Problem in Datei gefunden - Dem Kochrezept '' fehlt das erforderliche 'ingredient'-Argument." warning.config.recipe.missing_result: "Problem in Datei gefunden - Dem Rezept '' fehlt das erforderliche 'result'-Argument." warning.config.recipe.result.missing_id: "Problem in Datei gefunden - Dem Rezept '' fehlt das erforderliche Argument 'id' für das Rezeptresultat." diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 9df428604..56a24d8f5 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -65,6 +65,7 @@ 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.yaml.inconsistent_value_type: "Issue found in file - Found duplicated key '' at line with different value types, 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.boolean: "Issue found in file - Failed to load '': Cannot cast '' to boolean type for option ''." warning.config.type.float: "Issue found in file - Failed to load '': Cannot cast '' to float type for option ''." @@ -120,7 +121,8 @@ warning.config.image.invalid_hex_value: "Issue found in file - T 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." warning.config.recipe.invalid_type: "Issue found in file - The recipe '' is using an invalid recipe type ''." -warning.config.recipe.invalid_item: "Issue found in file - The recipe '' is using an invalid item ''." +warning.config.recipe.invalid_ingredient: "Issue found in file - The recipe '' is using an invalid ingredient ''." +warning.config.recipe.invalid_result: "Issue found in file - The recipe '' is using an invalid result ''." warning.config.recipe.missing_ingredient: "Issue found in file - The cooking recipe '' is missing the required 'ingredient' argument." warning.config.recipe.missing_result: "Issue found in file - The recipe '' is missing the required 'result' argument." warning.config.recipe.result.missing_id: "Issue found in file - The recipe '' is missing the required argument 'id' for recipe result." @@ -133,11 +135,19 @@ warning.config.recipe.smithing_transform.post_processor.missing_type: "I warning.config.recipe.smithing_transform.post_processor.invalid_type: "Issue found in file - The smithing transform recipe '' is using an invalid post processor type ''." warning.config.recipe.smithing_transform.post_processor.keep_component.missing_components: "Issue found in file - The smithing transform recipe '' is missing the required argument 'components' for post-processors 'keep_components'." 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.recipe.smithing_transform.missing_base: "Issue found in file - The smithing transform recipe '' is missing the required 'base' argument." +warning.config.recipe.smithing_trim.missing_base: "Issue found in file - The smithing trim recipe '' is missing the required 'base' argument." +warning.config.recipe.smithing_trim.missing_template_type: "Issue found in file - The smithing trim recipe '' is missing the required 'template-type' argument." +warning.config.recipe.smithing_trim.missing_addition: "Issue found in file - The smithing trim recipe '' is missing the required 'addition' argument." +warning.config.recipe.smithing_trim.missing_pattern: "Issue found in file - The smithing trim recipe '' is missing the required 'pattern' argument." +warning.config.recipe.brewing.missing_container: "Issue found in file - The brewing recipe '' is missing the required 'container' argument." +warning.config.recipe.brewing.missing_ingredient: "Issue found in file - The brewing recipe '' is missing the required 'ingredient' argument." 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.missing_value: "Issue found in file - The config '' is missing the template argument for ''. Please use the arguments option to configure or set a default value for this parameter." 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 ''." @@ -155,11 +165,19 @@ warning.config.furniture.hitbox.custom.invalid_entity: "Issue found in f 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.settings.equippable.missing_slot: "Issue found in file - The item '' is missing the required 'slot' argument for 'equippable' settings." +warning.config.item.settings.equipment.missing_asset_id: "Issue found in file - The item '' is missing the required 'asset-id' argument for 'equipment' settings." +warning.config.item.settings.equipment.invalid_asset_id: "Issue found in file - The item '' is using an invalid 'asset-id' argument for 'equipment' settings. This might be because you haven't created this equipment configuration or misspelled the asset-id." +warning.config.item.settings.projectile.missing_item: "Issue found in file - The item '' is missing the required 'item' argument for 'projectile' settings." +warning.config.item.data.attribute_modifiers.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for 'attribute-modifiers' data." +warning.config.item.data.attribute_modifiers.missing_amount: "Issue found in file - The item '' is missing the required 'amount' argument for 'attribute-modifiers' data." +warning.config.item.data.attribute_modifiers.missing_operation: "Issue found in file - The item '' is missing the required 'operation' argument for 'attribute-modifiers' data." +warning.config.item.data.attribute_modifiers.display.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for 'attribute-modifiers' display data." +warning.config.item.data.attribute_modifiers.display.missing_value: "Issue found in file - The item '' is missing the required 'value' argument for 'attribute-modifiers' display data." 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.item_model.conflict: "Issue found in file - The item '' is using an invalid 'item-model' option because this item model has been occupied by a vanilla item." 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." @@ -273,6 +291,7 @@ warning.config.block.behavior.stairs.missing_half: "Issue found in file warning.config.block.behavior.stairs.missing_shape: "Issue found in file - The block '' is missing the required 'shape' property for 'stairs_block' behavior." warning.config.block.behavior.pressure_plate.missing_powered: "Issue found in file - The block '' is missing the required 'powered' property for 'pressure_plate_block' behavior." warning.config.block.behavior.grass.missing_feature: "Issue found in file - The block '' is missing the required 'feature' argument for 'grass_block' behavior." +warning.config.block.behavior.double.missing_half: "Issue found in file - The block '' is missing the required 'half' property for 'double_block' behavior." warning.config.model.generation.missing_parent: "Issue found in file - The config '' is missing the required 'parent' argument in 'generation' section." warning.config.model.generation.invalid_display_position: "Issue found in file - The config '' is using an invalid display position '' in 'generation.display' section. Allowed display positions: []" warning.config.model.generation.invalid_gui_light: "Issue found in file - The config '' is using an invalid gui-light option '' in 'generation' section. Allowed gui light options: []" @@ -377,14 +396,18 @@ warning.config.function.remove_cooldown.missing_id: "Issue found in file warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." 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." warning.config.resource_pack.generation.missing_font_texture: "Font '' is missing required texture: ''" warning.config.resource_pack.generation.texture_not_in_atlas: "Texture '' is not listed in the atlas. You need to add the texture path to the atlas or enable 'obfuscation' option in config.yml." 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_block_model: "Block state '' is missing model file: ''" warning.config.resource_pack.generation.missing_parent_model: "Model '' cannot find parent model: ''" warning.config.resource_pack.generation.malformatted_json: "Json file '' is malformatted." -warning.config.resource_pack.invalid_overlay_format: "Issue found in config.yml at 'resource-pack.overlay-format' - Invalid overlay format ''. Overlay format must contain the placeholder '{version}'." \ No newline at end of file +warning.config.resource_pack.generation.missing_equipment_texture: "Equipment '' is missing texture ''" +warning.config.resource_pack.invalid_overlay_format: "Issue found in config.yml at 'resource-pack.overlay-format' - Invalid overlay format ''. Overlay format must contain the placeholder '{version}'." +warning.config.equipment.duplicate: "Issue found in file - Duplicated equipment ''. Please check if there is the same configuration in other files." +warning.config.equipment.missing_type: "Issue found in file - The equipment '' is missing the required 'type' argument." +warning.config.equipment.invalid_type: "Issue found in file - The equipment '' is using an invalid 'type' argument." +warning.config.equipment.invalid_sacrificed_armor: "Issue found in config.yml at 'equipment.sacrificed-vanilla-armor' - Invalid vanilla armor type ''." \ No newline at end of file diff --git a/common-files/src/main/resources/translations/es.yml b/common-files/src/main/resources/translations/es.yml index 6e489ea9e..9eb382a17 100644 --- a/common-files/src/main/resources/translations/es.yml +++ b/common-files/src/main/resources/translations/es.yml @@ -84,7 +84,8 @@ warning.config.image.invalid_hex_value: "Problema encontrado en el archi warning.config.recipe.duplicate: "Problema encontrado en el archivo - Receta duplicada ''. Verifica si hay la misma configuración en otros archivos." warning.config.recipe.missing_type: "Problema encontrado en el archivo - La receta '' carece del argumento requerido 'type'." warning.config.recipe.invalid_type: "Problema encontrado en el archivo - La receta '' está usando un tipo de receta inválido ''." -warning.config.recipe.invalid_item: "Problema encontrado en el archivo - La receta '' está usando un objeto inválido ''." +warning.config.recipe.invalid_ingredient: "Issue found in file - The recipe '' is using an invalid ingredient ''." +warning.config.recipe.invalid_result: "Issue found in file - The recipe '' is using an invalid result ''." warning.config.recipe.missing_ingredient: "Problema encontrado en el archivo - La receta de cocción '' carece del argumento requerido 'ingredient'." warning.config.recipe.missing_result: "Problema encontrado en el archivo - La receta '' carece del argumento requerido 'result'." warning.config.recipe.result.missing_id: "Problema encontrado en el archivo - La receta '' carece del argumento requerido 'id' para el resultado de la receta." diff --git a/common-files/src/main/resources/translations/ru_ru.yml b/common-files/src/main/resources/translations/ru_ru.yml new file mode 100644 index 000000000..73b8fa55b --- /dev/null +++ b/common-files/src/main/resources/translations/ru_ru.yml @@ -0,0 +1,391 @@ +# Не меняй это +lang-version: "${lang_version}" + +exception.invalid_syntax: "Неверный синтаксис. Правильный синтаксис: " +exception.invalid_argument: "Неверный аргумент. Причина: " +exception.invalid_sender: " не разрешено выполнять эту команду. Должен быть типа " +exception.unexpected: "Произошла внутренняя ошибка при попытке выполнить эту команду" +exception.no_permission: "Извините, но у вас нет разрешения на выполнение этой команды" +exception.no_such_command: "Неизвестная команда." +argument.entity.notfound.player: "" +argument.entity.notfound.entity: "" +argument.parse.failure.time: "'' не является действительным форматом времени" +argument.parse.failure.material: "'' не является действительным названием материала" +argument.parse.failure.enchantment: "'' не является действительным зачарованием" +argument.parse.failure.offlineplayer: "Игрок не найден для ввода ''" +argument.parse.failure.player: "Игрок не найден для ввода ''" +argument.parse.failure.world: "'' не является действительным миром Minecraft" +argument.parse.failure.location.invalid_format: "'' не является действительным местоположением. Требуемый формат ' " +argument.parse.failure.location.mixed_local_absolute: "Невозможно смешивать локальные и абсолютные координаты. (либо все координаты используют '^', либо ни одна не использует)" +argument.parse.failure.namespacedkey.namespace: "Неверное пространство имен ''. Должно быть [a-z0-9._-]" +argument.parse.failure.namespacedkey.key: "Неверный ключ ''. Должно быть [a-z0-9/._-]" +argument.parse.failure.namespacedkey.need_namespace: "Неверный ввод '', требуется явное пространство имен" +argument.parse.failure.boolean: "Не удалось проанализировать boolean из ''" +argument.parse.failure.number: "'' не является допустимым числом в диапазоне to " +argument.parse.failure.char: "'' не является допустимым символом" +argument.parse.failure.string: "'' не является допустимой строкой типа " +argument.parse.failure.uuid: "'' не является допустимым UUID" +argument.parse.failure.enum: "'' не является одним из следующих: " +argument.parse.failure.regex: "'' не соответствует ''" +argument.parse.failure.flag.unknown: "Неизвестный флаг ''" +argument.parse.failure.flag.duplicate_flag: "Дублирующийся флаг ''" +argument.parse.failure.flag.no_flag_started: "Нет запущенного флага. Не знаю, что делать с ''" +argument.parse.failure.flag.missing_argument: "Отсутствует аргумент для ''" +argument.parse.failure.flag.no_permission: "У вас нет разрешения на использование ''" +argument.parse.failure.color: "'' недопустимый цвет" +argument.parse.failure.duration: "'' не является форматом длительности" +argument.parse.failure.aggregate.missing: "Отсутствует компонент ''" +argument.parse.failure.aggregate.failure: "Неверный компонент '': " +argument.parse.failure.either: "Не удалось решить или из ''" +argument.parse.failure.namedtextcolor: "'' не является именованным цветом текста" +command.reload.config.success: "Конфигурации перезагружены в мс. (Асинхронный: мс | Синхронный: мс)" +command.reload.config.failure: "Ошибка перезагрузки конфигурации. Проверьте логи консоли." +command.reload.pack.success: "Пакет ресурсов перезагружен в мс." +command.reload.pack.failure: "Перезагрузка пакета ресурсов не удалась. Проверьте логи консоли." +command.reload.all.success: "Перезагрузка завершена в мс. (Асинхронный: мс | Синхронный: мс | Пак: мс)" +command.reload.all.failure: "Перезагрузка не удалась. Проверьте логи консоли." +command.item.get.success: "Получил " +command.item.get.failure.not_exist: "'>" +command.item.give.success.single: "':'':''>" +command.item.give.success.multiple: "':'':''>" +command.item.give.failure.not_exist: "'>" +command.search_recipe.not_found: "Рецепт для этого предмета не найден" +command.search_usage.not_found: "Для этого предмета не найдено ни одного использования" +command.search_recipe.no_item: "Пожалуйста, держите предмет перед выполнением этой команды." +command.search_usage.no_item: "Пожалуйста, держите предмет перед выполнением этой команды." +command.totem_animation.failure.not_totem: "Предмет '' это не minecraft:totem_of_undying" +command.resource.enable.success: "Включенный ресурс . Запусти /ce reload all для применения изменений" +command.resource.enable.failure.unknown: "Неизвестный ресурс " +command.resource.disable.success: "Отключенный ресурс . Запусти /ce reload all для применения изменений" +command.resource.disable.failure.unknown: "Unknown resource " +command.resource.list: "Включенные ресурсы(): Отключенные ресурсы(): " +command.upload.failure.not_supported: "Текущий метод хостинга '' не поддерживает загрузку пакетов ресурсов." +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: "Проблема найдена в файле - Не удалось загрузить '': Невозможно применить '' к integer типу для опции ''." +warning.config.type.boolean: "Проблема найдена в файле - Не удалось загрузить '': Невозможно применить '' к boolean типу для опции ''." +warning.config.type.float: "Проблема найдена в файле - Не удалось загрузить '': Невозможно применить '' к float типу для опции ''." +warning.config.type.double: "Проблема найдена в файле - Не удалось загрузить '': Невозможно применить '' к double типу для опции ''." +warning.config.type.quaternionf: "Проблема найдена в файле - Не удалось загрузить '': Невозможно применить '' к Quaternionf типу для опции ''." +warning.config.type.vector3f: "Проблема найдена в файле - Не удалось загрузить '': Невозможно применить '' к Vector3f типу для опции ''." +warning.config.type.snbt.invalid_syntax: "Проблема найдена в файле - Не удалось загрузить '': Неверный синтаксис snbt ''." +warning.config.number.missing_type: "Проблема найдена в файле - В конфигурации '' отсутствует требуемый аргумент 'type' для числового аргумента." +warning.config.number.invalid_type: "Проблема найдена в файле - Конфигурация '' использует недопустимый тип числового аргумента ''." +warning.config.number.missing_argument: "Проблема найдена в файле - В конфигурации '' отсутствует аргумент для 'number'." +warning.config.number.invalid_format: "Проблема найдена в файле - Конфигурация '' использует неверный числовой формат ''." +warning.config.number.fixed.missing_value: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'value' аргумент для 'constant' числа." +warning.config.number.fixed.invalid_value: "Проблема найдена в файле - Конфигурация '' использует недействительный 'value' аргумент '' для 'constant' числа." +warning.config.number.expression.missing_expression: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'expression' аргумент для 'expression' числа." +warning.config.number.uniform.missing_min: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'min' аргумент для 'uniform' числа." +warning.config.number.uniform.missing_max: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'max' аргумент для 'uniform' числа." +warning.config.condition.all_of.missing_terms: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'terms' аргумент для 'all_of' состояния." +warning.config.condition.all_of.invalid_terms_type: "Проблема найдена в файле - Конфигурация '' имеет неправильно настроенное 'all_of' состояние, 'terms' должен быть списком карт, текущий тип: ''." +warning.config.condition.any_of.missing_terms: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'terms' аргумент для 'any_of' состояния." +warning.config.condition.any_of.invalid_terms_type: "Проблема найдена в файле - Конфигурация '' имеет неправильно настроенное 'any_of' состояние, 'terms' должен быть списком карт, текущий тип: ''." +warning.config.condition.inverted.missing_term: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'term' аргумент для 'inverted' состояния." +warning.config.condition.inverted.invalid_term_type: "Проблема найдена в файле - Конфигурация '' имеет неправильно настроенное 'inverted' состояние, 'term' должен быть разделом конфигурации, текущий тип: ''." +warning.config.condition.enchantment.missing_predicate: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'predicate' аргумент для 'enchantment' состояния." +warning.config.condition.enchantment.invalid_predicate: "Проблема найдена в файле - Конфигурация '' использует недопустимый аргумент зачарования 'predicate' ''." +warning.config.condition.match_block_property.missing_properties: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'properties' аргумент для 'match_block_property' состояния." +warning.config.condition.match_item.missing_id: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'id' аргумент для 'match_item' состояния." +warning.config.condition.table_bonus.missing_enchantment: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'enchantment' аргумент для 'table_bonus' состояния." +warning.config.condition.table_bonus.missing_chances: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'chances' аргумент для 'table_bonus' состояния." +warning.config.condition.permission.missing_permission: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'permission' аргумент для 'permission' состояния." +warning.config.condition.string_equals.missing_value1: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'value1' аргумент для 'string_equals' состояния." +warning.config.condition.string_equals.missing_value2: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'value2' аргумент для 'string_equals' состояния." +warning.config.condition.string_contains.missing_value1: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'value1' аргумент для 'string_contains' состояния." +warning.config.condition.string_contains.missing_value2: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'value2' аргумент для 'string_contains' состояния." +warning.config.condition.string_regex.missing_value: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'value' аргумент для 'string_regex' состояния." +warning.config.condition.string_regex.missing_regex: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'regex' аргумент для 'string_regex' состояния." +warning.config.condition.expression.missing_expression: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'expression' аргумент для 'expression' состояния." +warning.config.condition.is_null.missing_argument: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'argument' аргумент для 'is_null' состояния." +warning.config.condition.hand.missing_hand: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'hand' аргумент для 'hand' состояния." +warning.config.condition.hand.invalid_hand: "Проблема найдена в файле - В конфигурации '' использует недействительный 'hand' аргумент '' для 'hand' состояния. Допустимые типы рук: []" +warning.config.condition.on_cooldown.missing_id: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'id' аргумент для 'on_cooldown' состояния." +warning.config.structure.not_section: "Проблема найдена в файле - В конфигурации '' ожидается, что это будет раздел конфигурации, хотя на самом деле это a(n) ''." +warning.config.image.duplicate: "Проблема найдена в файле - Дублированное изображение ''. Проверьте, есть ли такая же конфигурация в других файлах." +warning.config.image.missing_height: "Проблема найдена в файле - В изображении '' отсутствует необходимый 'height' аргумент." +warning.config.image.height_ascent_conflict: "Проблема найдена в файле - Изображение '' нарушает правило растрового изображения: 'height' аргумент '' не должен быть ниже 'ascent' аргумента ''." +warning.config.image.missing_file: "Проблема найдена в файле - В изображении '' отсутствует необходимый 'file' аргумент." +warning.config.image.invalid_file_chars: "Проблема найдена в файле - Изображение '' имеет 'file' аргумент '', который содержит недопустимые символы. Пожалуйста, прочтите https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.image.invalid_font_chars: "Проблема найдена в файле - Изображение'' имеет 'font' аргумент '', который содержит недопустимые символы. Пожалуйста, прочтите https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.image.missing_char: "Проблема найдена в файле - В изображении '' отсутствует необходимый 'char' аргумент." +warning.config.image.codepoint_conflict: "Проблема найдена в файле - Изображение '' использует символ '()' в шрифте который был использован другим изображением ''." +warning.config.image.invalid_codepoint_grid: "Проблема найдена в файле - Изображение '' имеет недействительную 'chars' сетку кодовых точек." +warning.config.image.invalid_char: "Проблема найдена в файле - Изображение '' имеет параметр char, содержащий комбинированные символы, что может привести к разделению изображения." +warning.config.image.invalid_hex_value: "Проблема найдена в файле - Изображение '' использует символ юникода '' это недопустимое шестнадцатеричное (radix 16) значение." +warning.config.recipe.duplicate: "Проблема найдена в файле - Дублированный рецепт ''. Проверьте, есть ли такая же конфигурация в других файлах." +warning.config.recipe.missing_type: "Проблема найдена в файле - В рецепте '' отсутствует необходимый 'type' аргумент." +warning.config.recipe.invalid_type: "Проблема найдена в файле - Рецепт '' использует недопустимый тип рецепта ''." +warning.config.recipe.invalid_ingredient: "Issue found in file - The recipe '' is using an invalid ingredient ''." +warning.config.recipe.invalid_result: "Issue found in file - The recipe '' is using an invalid result ''." +warning.config.recipe.missing_ingredient: "Проблема найдена в файле - В рецепт приготовления '' отсутствует необходимый 'ingredient' аргумент." +warning.config.recipe.missing_result: "Проблема найдена в файле - В рецепте '' отсутствует необходимый 'result' аргумент." +warning.config.recipe.result.missing_id: "Проблема найдена в файле - В рецепте '' отсутствует необходимый аргумент 'id' для результата рецепта." +warning.config.recipe.crafting.invalid_category: "Проблема найдена в файле - Рецепт крафта '' использует недопустимую категорию ''. Разрешенные категории: []." +warning.config.recipe.cooking.invalid_category: "Проблема найдена в файле - Рецепт приготовления '' использует недопустимую категорию ''. Разрешенные категории: []." +warning.config.recipe.shaped.missing_pattern: "Проблема найдена в файле - В shaped рецепт '' отсутствует необходимый аргумент 'pattern'." +warning.config.recipe.shaped.invalid_pattern: "Проблема найдена в файле - Shaped рецепт '' использует недопустимый шаблон ''." +warning.config.recipe.shaped.invalid_symbol: "Проблема найдена в файле - Shaped рецепт '' использует недопустимый символ '' в шаблоне." +warning.config.recipe.smithing_transform.post_processor.missing_type: "Проблема найдена в файле - В рецепте трансформации кузнечного дела '' отсутствует необходимый аргумент 'type' для одного из постпроцессоров." +warning.config.recipe.smithing_transform.post_processor.invalid_type: "Проблема найдена в файле - Рецепт трансформации кузнечного дела '' использует недопустимый тип постпроцессора ''." +warning.config.recipe.smithing_transform.post_processor.keep_component.missing_components: "Проблема найдена в файле - В рецепте трансформации кузнечного дела '' отсутствует необходимый аргумент 'components' для постпроцессоров 'keep_components'." +warning.config.recipe.smithing_transform.post_processor.keep_component.missing_tags: "Проблема найдена в файле - В рецепте трансформации кузнечного дела '' отсутствует необходимый аргумент 'tags' для постпроцессоров 'keep_tags'." +warning.config.i18n.unknown_locale: "Проблема найдена в файле - Неизвестный locale ''." +warning.config.template.duplicate: "Проблема найдена в файле - Дублированный шаблон ''. Проверьте, есть ли такая же конфигурация в других файлах." +warning.config.template.invalid: "Проблема найдена в файле - Конфигурация '' использует недействительный шаблон ''." +warning.config.template.argument.self_increase_int.invalid_range: "Проблема найдена в файле - Шаблон '' использует 'from' '' больше, чем 'to' '' в 'self_increase_int' аргументе." +warning.config.template.argument.list.invalid_type: "Проблема найдена в файле - Шаблон '' использует 'list' аргумент, который ожидает 'List' как аргумент, в то время как входной аргумент a(n) ''." +warning.config.vanilla_loot.missing_type: "Проблема найдена в файле - В ванильном луте '' отсутствует необходимый 'type' аргумент." +warning.config.vanilla_loot.invalid_type: "Проблема найдена в файле - Ванильный лут '' использует недопустимый тип ''. Разрешенные типы: []." +warning.config.vanilla_loot.block.invalid_target: "Проблема найдена в файле - Неверная цель блока '' в ванильном луте. ''." +warning.config.sound.duplicate: "Проблема найдена в файле - Дублированный звук ''. Проверьте, есть ли такая же конфигурация в других файлах." +warning.config.sound.missing_sounds: "Проблема найдена в файле - В звуке '' отсутствует необходимый 'sounds' аргумент." +warning.config.sound.missing_name: "Проблема найдена в файле - В звуке '' отсутствует необходимый 'name' аргумент." +warning.config.jukebox_song.duplicate: "Проблема найдена в файле - Дублированная песня музыкального автомата ''. Проверьте, есть ли такая же конфигурация в других файлах." +warning.config.jukebox_song.missing_sound: "Проблема найдена в файле - В песне музыкального автомата '' отсутствует необходимый 'sound' аргумент." +warning.config.furniture.duplicate: "Проблема найдена в файле - Дублированная мебель ''. Проверьте, есть ли такая же конфигурация в других файлах." +warning.config.furniture.missing_placement: "Проблема найдена в файле - В мебели '' отсутствует необходимый 'placement' аргумент." +warning.config.furniture.element.missing_item: "Проблема найдена в файле - В мебели '' отсутствует необходимый 'item' аргумент для одного из его элементов." +warning.config.furniture.settings.unknown: "Проблема найдена в файле - Мебель '' использует неизвестный тип настройки ''." +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.settings.equippable.missing_slot: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'slot' аргумент для 'equippable' настроек." +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: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'model' раздел для поддержки пакета ресурсов 1.21.4+." +warning.config.item.behavior.missing_type: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'type' аргумент для behavior предмета." +warning.config.item.behavior.invalid_type: "Проблема найдена в файле - Предмет '' использует недопустимый элемент behavior тип ''." +warning.config.item.behavior.block.missing_block: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'block' аргумент для 'block_item' behavior." +warning.config.item.behavior.furniture.missing_furniture: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'furniture' аргумент для 'furniture_item' behavior." +warning.config.item.behavior.liquid_collision.missing_block: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'block' аргумент для 'liquid_collision_block_item' behavior." +warning.config.item.legacy_model.missing_path: "Проблема найдена в файле - В предмете '' отсутствует требование 'path' аргумента для legacy-model." +warning.config.item.legacy_model.overrides.missing_path: "Проблема найдена в файле - В предмете '' отсутствует требование 'path' аргумента для legacy-model переопределения." +warning.config.item.legacy_model.overrides.missing_predicate: "Проблема найдена в файле - В предмете '' отсутствует требование 'predicate' аргумента для legacy-model переопределения." +warning.config.item.legacy_model.cannot_convert: "Проблема найдена в файле - Невозможно конвертировать элементы 1.21.4+ в устаревший формат для элемента ''. Пожалуйста, создайте вручную 'legacy-model' раздел для этого элемента." +warning.config.item.model.invalid_type: "Проблема найдена в файле - Предмет '' использует недопустимый тип модели ''." +warning.config.item.model.tint.missing_type: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'type' аргумент для оттенка." +warning.config.item.model.tint.invalid_type: "Проблема найдена в файле - Предмет '' использует недопустимый тип оттенка ''." +warning.config.item.model.tint.constant.missing_value: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'value' аргумент для постоянного оттенка." +warning.config.item.model.tint.grass.invalid_temp: "Проблема найдена в файле - Предмет '' использует недопустимую температуру '' для оттенка травы, который, как ожидается, будет между 0 и 1." +warning.config.item.model.tint.grass.invalid_downfall: "Проблема найдена в файле - Предмет '' использует недействительный downfall '' для оттенка травы, который, как ожидается, будет между 0 и 1." +warning.config.item.model.tint.invalid_value: "Проблема найдена в файле - Предмет '' использует недопустимый оттенок ''." +warning.config.item.model.base.missing_path: "Проблема найдена в файле - Предмет '' отсутствует необходимый 'path' аргумент для модели 'minecraft:model'." +warning.config.item.model.base.invalid_path: "Проблема найдена в файле - Предмет '' имеет недействительный 'path' аргумент '' для модели 'minecraft:model' которая содержит недопустимые символы. Пожалуйста, прочтите https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.item.model.condition.missing_property: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'property' аргумент для модели 'minecraft:condition'." +warning.config.item.model.condition.invalid_property: "Проблема найдена в файле - Предмет '' использует недопустимое свойство '' для модели 'minecraft:condition'." +warning.config.item.model.condition.missing_on_true: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'on-true' аргумент для модели 'minecraft:condition'." +warning.config.item.model.condition.missing_on_false: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'on-false' аргумент для для модели 'minecraft:condition'." +warning.config.item.model.condition.keybind.missing_keybind: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'keybind' аргумент для свойства 'minecraft:keybind_down'." +warning.config.item.model.condition.has_component.missing_component: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'component' аргумент для свойства 'minecraft:has_component'." +warning.config.item.model.condition.component.missing_predicate: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'predicate' аргумент для свойства 'minecraft:component'." +warning.config.item.model.condition.component.missing_value: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'value' аргумент для свойства 'minecraft:component'." +warning.config.item.model.composite.missing_models: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'models' аргумент для 'minecraft:composite' модели." +warning.config.item.model.range_dispatch.missing_property: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'property' аргумент для модели 'minecraft:range_dispatch'." +warning.config.item.model.range_dispatch.invalid_property: "Проблема найдена в файле - Предмет '' имеет недействительное свойство '' для модели 'minecraft:range_dispatch'." +warning.config.item.model.range_dispatch.missing_entries: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'entries' аргумент для модели 'minecraft:composite'." +warning.config.item.model.range_dispatch.entry.missing_model: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'model' аргумент для одной из записей в модели 'minecraft:composite'." +warning.config.item.model.range_dispatch.compass.missing_target: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'target' аргумент для свойства 'minecraft:compass'." +warning.config.item.model.range_dispatch.time.missing_source: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'source' аргумент для свойства 'minecraft:time'." +warning.config.item.model.select.missing_property: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'property' аргумент для модели 'minecraft:select'." +warning.config.item.model.select.invalid_property: "Проблема найдена в файле - Предмет '' имеет недействительное свойство '' для модели 'minecraft:select'." +warning.config.item.model.select.missing_cases: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'cases' аргумент для модели 'minecraft:select'." +warning.config.item.model.select.case.missing_when: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'when' аргумент для одного из случаев в модели 'minecraft:select'." +warning.config.item.model.select.case.missing_model: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'model' аргумент для одного из случаев в модели 'minecraft:select'." +warning.config.item.model.select.block_state.missing_property: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'block-state-property' аргумент для свойства 'minecraft:block_state'." +warning.config.item.model.select.local_time.missing_pattern: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'pattern' аргумент для свойства 'minecraft:local_time'." +warning.config.item.model.select.component.missing_component: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'component' аргумент для свойства 'minecraft:component'." +warning.config.item.model.special.missing_type: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'type' аргумент для модели 'minecraft:special'." +warning.config.item.model.special.missing_path: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'path' аргумент для модели 'minecraft:special'." +warning.config.item.model.special.invalid_path: "Проблема найдена в файле - Предмет '' has an invalid 'path' argument '' для модели 'minecraft:special' которая содержит недопустимые символы. Пожалуйста, прочтите https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.item.model.special.invalid_type: "Проблема найдена в файле - В предмете '' имеет недействительный тип '' для модели 'minecraft:special'." +warning.config.item.model.special.banner.missing_color: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'color' аргумент для специальной модели 'minecraft:banner'." +warning.config.item.model.special.bed.missing_texture: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'texture' аргумент для специальной модели 'minecraft:bed'." +warning.config.item.model.special.sign.missing_wood_type: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'wood-type' аргумент для специальной модели 'minecraft:hanging_sign'/'minecraft:standing_sign'." +warning.config.item.model.special.sign.missing_texture: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'texture' аргумент для специальной модели 'minecraft:hanging_sign'/'minecraft:standing_sign'." +warning.config.item.model.special.chest.missing_texture: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'texture' аргумент для специальной модели 'minecraft:chest'." +warning.config.item.model.special.chest.invalid_openness: "Проблема найдена в файле - Предмет '' имеет недействительное 'openness' значение '' для специальной модели 'minecraft:chest'. Действительный диапазон '0~1.'" +warning.config.item.model.special.shulker_box.missing_texture: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'texture' аргумент для специальной модели 'minecraft:shulker_box'." +warning.config.item.model.special.shulker_box.invalid_openness: "Проблема найдена в файле - Предмет '' имеет недействительный 'openness' value '' for специальной модели 'minecraft:shulker_box'. Действительный диапазон '0~1.'" +warning.config.item.model.special.head.missing_kind: "Проблема найдена в файле - В предмете '' отсутствует необходимый 'kind' аргумент для специальной модели 'minecraft:head'." +warning.config.block.duplicate: "Проблема найдена в файле - Дублированный блок ''. Проверьте, есть ли такая же конфигурация в других файлах." +warning.config.block.missing_state: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'state' аргумент." +warning.config.block.state.property.missing_type: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'type' аргумент для свойства ''." +warning.config.block.state.property.invalid_type: "Проблема найдена в файле - Блок '' использует недопустимый аргумент типа '' для свойства ''." +warning.config.block.state.property.integer.invalid_range: "Проблема найдена в файле - Блок '' использует недействительный 'range' аргумент '' для integer свойства ''. Правильный синтаксис: 1~2." +warning.config.block.state.property.invalid_format: "Проблема найдена в файле - Блок '' имеет недействительный формат свойства состояния блока ''." +warning.config.block.state.missing_real_id: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'id' аргумент для 'state'. 'id' это идентификатор блока на стороне сервера, который уникален для каждого типа состояния блока. Если вы создаете блок на стороне сервера с 'note_block' и идентификатор 30, тогда реальный идентификатор блока будет 'craftengine:note_block_30'." +warning.config.block.state.missing_state: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'state' аргумент для 'state'." +warning.config.block.state.missing_properties: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'properties' раздел для 'states'." +warning.config.block.state.missing_appearances: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'appearances' раздел для 'states'." +warning.config.block.state.missing_variants: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'variants' раздел для 'states'." +warning.config.block.state.variant.missing_appearance: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'appearance' аргумент для варианта ''." +warning.config.block.state.variant.invalid_appearance: "Проблема найдена в файле - Блок '' имеет ошибку, что вариант '' использует несуществующий внешний вид ''." +warning.config.block.state.invalid_vanilla: "Проблема найдена в файле - Блок '' имеет недействительное состояние ванильного блока ''." +warning.config.block.state.unavailable_vanilla: "Проблема найдена в файле - Блок '' использует недоступное состояние ванильного блока ''. Пожалуйста, освободите это состояние в mappings.yml." +warning.config.block.state.invalid_vanilla_id: "Проблема найдена в файле - Блок '' использует состояние ванильного блока '', что превышает доступный диапазон слотов '0~'." +warning.config.block.state.conflict: "Проблема найдена в файле - Блок '' использует состояние ванильного блока '' которое занято ''." +warning.config.block.state.bind_failed: "Проблема найдена в файле - Блоку '' не удалось привязать реальное состояние блока для '', так как состояние занято ''." +warning.config.block.state.missing_model: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'model' или 'models' аргумент." +warning.config.block.state.invalid_real_id: "Проблема найдена в файле - Блок '' использует реальное состояние блока '', которое превышает доступный диапазон слотов '0~'. Рассмотрите возможность добавления большего количества реальных состояний в 'additional-real-blocks.yml' если слоты израсходованы." +warning.config.block.state.model.missing_path: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'path' опция для 'model'." +warning.config.block.state.model.invalid_path: "Проблема найдена в файле - Блок '' имеет 'path' аргумент '' содержит недопустимые символы. Пожалуйста, прочтите https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.block.settings.unknown: "Проблема найдена в файле - Блок '' использует неизвестный тип настройки ''." +warning.config.block.behavior.missing_type: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'type' аргумент для его блочного behavior." +warning.config.block.behavior.invalid_type: "Проблема найдена в файле - Блок '' имеет недействительный блочный behavior тип ''." +warning.config.block.behavior.concrete.missing_solid: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'solid-block' вариант для 'concrete_block' behavior." +warning.config.block.behavior.crop.missing_age: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'age' свойство для 'crop_block' behavior." +warning.config.block.behavior.sugar_cane.missing_age: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'age' свойство для 'sugar_cane_block' behavior." +warning.config.block.behavior.leaves.missing_persistent: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'persistent' свойство для 'leaves_block' behavior." +warning.config.block.behavior.leaves.missing_distance: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'distance' свойство для 'leaves_block' behavior." +warning.config.block.behavior.lamp.missing_lit: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'lit' свойство для 'lamp_block' behavior." +warning.config.block.behavior.sapling.missing_stage: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'stage' свойство для 'sapling_block' behavior." +warning.config.block.behavior.sapling.missing_feature: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'feature' аргумент для 'sapling_block' behavior." +warning.config.block.behavior.strippable.missing_stripped: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'stripped' аргумент для 'strippable_block' behavior." +warning.config.block.behavior.door.missing_half: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'half' свойство для 'door_block' behavior." +warning.config.block.behavior.door.missing_facing: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'facing' свойство для 'door_block' behavior." +warning.config.block.behavior.door.missing_hinge: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'hinge' свойство для 'door_block' behavior." +warning.config.block.behavior.door.missing_open: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'open' свойство для 'door_block' behavior." +warning.config.block.behavior.door.missing_powered: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'powered' свойство для 'door_block' behavior." +warning.config.block.behavior.trapdoor.missing_half: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'half' свойство для 'trapdoor_block' behavior." +warning.config.block.behavior.trapdoor.missing_facing: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'facing' свойство для 'trapdoor_block' behavior." +warning.config.block.behavior.trapdoor.missing_open: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'open' свойство для 'trapdoor_block' behavior." +warning.config.block.behavior.trapdoor.missing_powered: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'powered' свойство для 'trapdoor_block' behavior." +warning.config.block.behavior.stackable.missing_property: "Проблема найдена в файле - В блоке '' отсутствует необходимый '' свойство для 'stackable_block' behavior." +warning.config.block.behavior.stackable.missing_items: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'items' аргумент для 'stackable_block' behavior." +warning.config.block.behavior.fence_gate.missing_facing: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'facing' аргумент для 'fence_gate_block' behavior." +warning.config.block.behavior.fence_gate.missing_in_wall: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'in_wall' аргумент для 'fence_gate_block' behavior." +warning.config.block.behavior.fence_gate.missing_open: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'powered' аргумент для 'fence_gate_block' behavior." +warning.config.block.behavior.fence_gate.missing_powered: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'open' аргумент для 'fence_gate_block' behavior." +warning.config.block.behavior.trapdoor.missing_type: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'type' свойство для 'slab_block' behavior." +warning.config.block.behavior.stairs.missing_facing: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'facing' свойство для 'stairs_block' behavior." +warning.config.block.behavior.stairs.missing_half: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'half' свойство для 'stairs_block' behavior." +warning.config.block.behavior.stairs.missing_shape: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'shape' свойство для 'stairs_block' behavior." +warning.config.block.behavior.pressure_plate.missing_powered: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'powered' свойство для 'pressure_plate_block' behavior." +warning.config.block.behavior.grass.missing_feature: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'feature' аргумент для 'grass_block' behavior." +warning.config.model.generation.missing_parent: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'parent' аргумент в 'generation' разделе." +warning.config.model.generation.invalid_display_position: "Проблема найдена в файле - Конфигурация '' имеет недействительное положение отображения '' в 'generation.display' разделе. Разрешенные позиции отображения: []" +warning.config.model.generation.invalid_gui_light: "Проблема найдена в файле - Конфигурация '' имеет недействительную gui-light опцию '' в 'generation' разделе. Допустимые gui light опции: []" +warning.config.model.generation.conflict: "Проблема найдена в файле - Не удалось создать модель для '' поскольку две или более конфигураций пытаются сгенерировать разные модели JSON с одним и тем же путем: ''." +warning.config.model.generation.texture.invalid: "Проблема найдена в файле - Конфигурация '' имеет текстуру '' с путем '', который содержит недопустимые символы. Пожалуйста, прочтите https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.model.generation.parent.invalid: "Проблема найдена в файле - Конфигурация '' имеет родительский аргумент '', который содержит недопустимые символы. Пожалуйста, прочтите https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.emoji.missing_keywords: "Проблема найдена в файле - В эмодзи '' отсутствует необходимый 'keywords' аргумент." +warning.config.emoji.duplicate: "Проблема найдена в файле - Дублированные эмодзи ''. Проверьте, есть ли такая же конфигурация в других файлах." +warning.config.emoji.invalid_image: "Проблема найдена в файле - Эмодзи '' имеет недействительный 'image' аргумент ''." +warning.config.advancement.duplicate: "Проблема найдена в файле - Дублированное достижение ''. Проверьте, есть ли такая же конфигурация в других файлах." +warning.config.loot_table.missing_pools: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в которой отсутствует необходимый 'pools' аргумент." +warning.config.loot_table.invalid_pools_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, 'pools' должен быть списком строк/карт, текущий тип: ''." +warning.config.loot_table.invalid_conditions_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, 'conditions' должен быть списком карт, текущий тип: ''." +warning.config.loot_table.invalid_functions_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, 'functions' должен быть список карт, текущий тип: ''." +warning.config.loot_table.invalid_entries_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, 'entries' должен быть список карт, текущий тип: ''." +warning.config.loot_table.function.missing_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в одной из функций отсутствует необходимый 'type' аргумент." +warning.config.loot_table.function.invalid_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, одна из функций имеет недействительный тип функции ''." +warning.config.loot_table.function.apply_bonus.missing_enchantment: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в функции 'apply_bonus' отсутствует необходимый 'enchantment' аргумент." +warning.config.loot_table.function.apply_bonus.missing_formula: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в функции 'apply_bonus' отсутствует необходимый 'formula' аргумент." +warning.config.loot_table.function.drop_exp.missing_count: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в функции 'drop_exp' отсутствует необходимый 'count' аргумент." +warning.config.loot_table.function.set_count.missing_count: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в функции 'set_count' отсутствует необходимый 'count' аргумент." +warning.config.loot_table.entry.missing_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в одной из записей отсутствует необходимый 'type' аргумент." +warning.config.loot_table.entry.invalid_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, одна из записей имеет недействительный тип записи ''." +warning.config.loot_table.entry.exp.missing_count: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в записи 'exp' отсутствует необходимый 'count' аргумент." +warning.config.loot_table.entry.item.missing_item: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в записи 'item' отсутствует необходимый 'item' аргумент." +warning.config.loot_table.condition.missing_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, в одном из условий отсутствует необходимый 'type' аргумент." +warning.config.loot_table.condition.invalid_type: "Проблема найдена в файле - '' имеет неправильно настроенную таблицу добычи, одно из условий имеет недействительный тип условия ''." +warning.config.host.missing_type: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'type' аргумент для хостинга." +warning.config.host.invalid_type: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Тип хоста '' недействителен. Пожалуйста, прочитайте https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host." +warning.config.host.external.missing_url: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'url' аргумент для внешнего хоста." +warning.config.host.alist.missing_api_url: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'api-url' аргумент для alist хостинга." +warning.config.host.alist.missing_username: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'username' аргумент или переменная среды 'CE_ALIST_USERNAME' для alist хостинга." +warning.config.host.alist.missing_password: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'password' аргумент или переменная среды 'CE_ALIST_PASSWORD' для alist хостинга." +warning.config.host.alist.missing_upload_path: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'upload-path' аргумент для alist хостинга." +warning.config.host.dropbox.missing_app_key: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'app-key' аргумент или переменная среды 'CE_DROPBOX_APP_KEY' для dropbox хостинга." +warning.config.host.dropbox.missing_app_secret: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'app-secret' аргумент или переменная среды 'CE_DROPBOX_APP_SECRET' для dropbox хостинга." +warning.config.host.dropbox.missing_refresh_token: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'refresh-token' аргумент или переменная среды 'CE_DROPBOX_REFRESH_TOKEN' для dropbox хостинга." +warning.config.host.dropbox.missing_upload_path: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'upload-path' аргумент для dropbox хостинга." +warning.config.host.lobfile.missing_api_key: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'api-key' аргумент для lobfile хостинга." +warning.config.host.onedrive.missing_client_id: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'client-id' аргумент или переменная среды 'CE_ONEDRIVE_CLIENT_ID' для onedrive хостинга." +warning.config.host.onedrive.missing_client_secret: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'client-secret' аргумент или переменная среды 'CE_ONEDRIVE_CLIENT_SECRET' для onedrive хостинга." +warning.config.host.onedrive.missing_refresh_token: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'refresh-token' аргумент или переменная среды 'CE_ONEDRIVE_REFRESH_TOKEN' для onedrive хостинга." +warning.config.host.onedrive.missing_upload_path: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'upload-path' аргумент для onedrive хостинга." +warning.config.host.s3.missing_endpoint: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'endpoint' аргумент для s3 хостинга." +warning.config.host.s3.missing_bucket: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'bucket' аргумент для s3 хостинга." +warning.config.host.s3.missing_access_key: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'access-key-id' аргумент или переменная среды 'CE_S3_ACCESS_KEY_ID' для s3 хостинга." +warning.config.host.s3.missing_secret: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'access-key-secret' аргумент или переменная среды 'CE_S3_ACCESS_KEY_SECRET' для s3 хостинга." +warning.config.host.s3.missing_upload_path: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'upload-path' аргумент для s3 хостинга." +warning.config.host.self.missing_ip: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'ip' аргумент для self хостинга." +warning.config.host.self.invalid_port: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Invalid port '' для self хостинга." +warning.config.host.self.invalid_url: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Invalid url '' для self хостинга." +warning.config.host.gitlab.missing_url: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'gitlab-url' аргумент для gitlab хостинга." +warning.config.host.gitlab.missing_token: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'access-token' аргумент для gitlab хостинга." +warning.config.host.gitlab.missing_project: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'project-id' аргумент для gitlab хостинга." +warning.config.host.proxy.missing_host: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'host' аргумент для прокси." +warning.config.host.proxy.missing_port: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'port' аргумент для прокси." +warning.config.host.proxy.missing_scheme: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Отсутствует обязательный 'scheme' аргумент для прокси." +warning.config.host.proxy.invalid: "Проблема обнаружена в config.yml по адресу 'resource-pack.delivery.hosting' - Недействительное прокси ''." +warning.config.conflict_matcher.missing_type: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'type' аргумент для одного из handlers." +warning.config.conflict_matcher.invalid_type: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Одно из условий использует недопустимый тип ''." +warning.config.conflict_matcher.exact.missing_path: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'path' аргумент для 'exact' matcher." +warning.config.conflict_matcher.contains.missing_path: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'path' аргумент для 'contains' matcher." +warning.config.conflict_matcher.filename.missing_name: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'path' аргумент для 'filename' matcher." +warning.config.conflict_matcher.pattern.missing_pattern: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'pattern' аргумент для 'pattern' matcher." +warning.config.conflict_matcher.parent_prefix.missing_prefix: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'prefix' аргумент для 'parent_path_prefix' matcher." +warning.config.conflict_matcher.parent_suffix.missing_suffix: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'suffix' аргумент для 'parent_path_suffix' matcher." +warning.config.conflict_matcher.inverted.missing_term: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'term' аргумент для 'inverted' matcher." +warning.config.conflict_matcher.all_of.missing_terms: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'terms' аргумент для 'all_of' matcher." +warning.config.conflict_matcher.any_of.missing_terms: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'terms' аргумент для 'any_of' matcher." +warning.config.conflict_resolution.missing_type: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Отсутствует обязательный 'type' аргумент для одной из резолюций." +warning.config.conflict_resolution.invalid_type: "Проблема обнаружена в config.yml по адресу 'resource-pack.duplicated-files-handler' - Одна из резолюций использует недопустимый тип ''." +warning.config.event.missing_trigger: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'on' аргумент для триггеров событий." +warning.config.event.invalid_trigger: "Проблема найдена в файле - Конфигурация '' имеет недействительный триггер события ''." +warning.config.event.condition.missing_type: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'type' аргумент для условия события." +warning.config.event.condition.invalid_type: "Проблема найдена в файле - В конфигурации '' имеет недействительный 'type' аргумент '' условия события." +warning.config.function.missing_type: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'type' аргумент для функции." +warning.config.function.invalid_type: "Проблема найдена в файле - Конфигурация '' имеет недействительный тип функции ''." +warning.config.function.command.missing_command: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'command' аргумент для 'command' функции." +warning.config.function.actionbar.missing_actionbar: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'actionbar' аргумент для 'actionbar' функции." +warning.config.function.message.missing_message: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'message' аргумент для 'message' функции." +warning.config.function.open_window.missing_gui_type: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'gui-type' аргумент для 'open_window' функции." +warning.config.function.open_window.invalid_gui_type: "Проблема найдена в файле - Конфигурация '' имеет недействительный gui type for 'open_window' функции. Разрешенные типы: []." +warning.config.function.run.missing_functions: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'functions' аргумент для 'run' функции." +warning.config.function.place_block.missing_block_state: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'block-state' аргумент для 'place_block' функции." +warning.config.function.set_food.missing_food: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'food' аргумент для 'set_food' функции." +warning.config.function.set_saturation.missing_saturation: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'saturation' аргумент для 'set_saturation' функции." +warning.config.function.play_sound.missing_sound: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'sound' аргумент для 'play_sound' функции." +warning.config.function.particle.missing_particle: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'particle' аргумент для 'particle' функции." +warning.config.function.particle.missing_color: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'color' аргумент для 'particle' функции." +warning.config.function.particle.missing_from: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'from' аргумент для 'particle' функции." +warning.config.function.particle.missing_to: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'to' аргумент для 'particle' функции." +warning.config.function.particle.missing_item: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'item' аргумент для 'particle' fфункции." +warning.config.function.particle.missing_block_state: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'block-state' аргумент для 'particle' функции." +warning.config.function.leveler_exp.missing_count: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'count' аргумент для 'leveler_exp' функции." +warning.config.function.leveler_exp.missing_leveler: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'leveler' аргумент для 'leveler_exp' функции." +warning.config.function.leveler_exp.missing_plugin: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'plugin' аргумент для 'leveler_exp' функции." +warning.config.function.remove_potion_effect.missing_potion_effect: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'potion-effect' аргумент для 'remove_potion_effect' функции." +warning.config.function.potion_effect.missing_potion_effect: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'potion-effect' аргумент для 'potion_effect' функции." +warning.config.function.set_cooldown.missing_time: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'time' аргумент для 'set_cooldown' функции." +warning.config.function.set_cooldown.missing_id: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'id' аргумент для 'set_cooldown' функции." +warning.config.function.remove_cooldown.missing_id: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'id' аргумент для 'remove_cooldown' функции." +warning.config.selector.missing_type: "Проблема найдена в файле - В конфигурации '' отсутствует необходимый 'type' аргумент для selector." +warning.config.selector.invalid_type: "Проблема найдена в файле - Конфигурация '' имеет недействительный selector тип ''." +warning.config.selector.invalid_target: "Проблема найдена в файле - Конфигурация '' имеет недействительную selector цель ''." +warning.config.resource_pack.item_model.conflict.vanilla: "Не удалось создать модель элемента для '', потому что эта модель предмета занята ванильным предметом." +warning.config.resource_pack.item_model.already_exist: "Не удалось создать модель элемента для '', потому что файл '' уже существует." +warning.config.resource_pack.model.generation.already_exist: "Не удалось создать модель, так как файл модели '' уже существует." +warning.config.resource_pack.generation.missing_font_texture: "В шрифте '' отсутствует обязательная текстура: ''" +warning.config.resource_pack.generation.texture_not_in_atlas: "Текстура '' не указана в атласе. Вам нужно добавить путь к текстуре в атлас или включить 'obfuscation' опцию в config.yml." +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: "Модель '' не может найти родительскую модель: ''" +warning.config.resource_pack.generation.malformatted_json: "Json файл '' имеет неверный формат." +warning.config.resource_pack.invalid_overlay_format: "Проблема обнаружена в config.yml по адресу 'resource-pack.overlay-format' - Неверный формат наложения ''. Формат наложения должен содержать заполнитель '{version}'." diff --git a/common-files/src/main/resources/translations/tr.yml b/common-files/src/main/resources/translations/tr.yml index 8cdcd859c..c8d9cc602 100644 --- a/common-files/src/main/resources/translations/tr.yml +++ b/common-files/src/main/resources/translations/tr.yml @@ -83,7 +83,8 @@ warning.config.image.invalid_hex_value: " dosyasında sorun bulun 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." warning.config.recipe.invalid_type: " dosyasında sorun bulundu - '' tarifi geçersiz bir tarif türü '' kullanıyor." -warning.config.recipe.invalid_item: " dosyasında sorun bulundu - '' tarifi geçersiz bir eşya '' kullanıyor." +warning.config.recipe.invalid_ingredient: "Issue found in file - The recipe '' is using an invalid ingredient ''." +warning.config.recipe.invalid_result: "Issue found in file - The recipe '' is using an invalid result ''." warning.config.recipe.missing_ingredient: " dosyasında sorun bulundu - '' pişirme tarifi gerekli 'ingredient' argümanı eksik." warning.config.recipe.missing_result: " dosyasında sorun bulundu - '' tarifi gerekli 'result' argümanı eksik." warning.config.recipe.result.missing_id: " dosyasında sorun bulundu - '' tarifi, tarif sonucu için gerekli 'id' 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 2768ad0a4..11b6758f2 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -65,7 +65,7 @@ command.send_resource_pack.success.single: "发送资源包给 发送资源包给 个玩家" warning.config.pack.duplicated_files: "发现重复文件 请通过 config.yml 的 'resource-pack.duplicated-files-handler' 部分解决" warning.config.yaml.duplicated_key: "在文件 发现问题 - 在第行发现重复的键 '', 这可能会导致一些意料之外的问题." -warning.config.yaml.key_path_conflict: "在文件 发现问题 - 在第行发现重复且值类型不同的键 '', 这可能会导致一些意料之外的问题." +warning.config.yaml.inconsistent_value_type: "在文件 发现问题 - 在第行发现重复且值类型不同的键 '', 这可能会导致一些意料之外的问题." warning.config.type.int: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为整数类型 (选项 '')" warning.config.type.float: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为浮点数类型 (选项 '')" warning.config.type.boolean: "在文件 发现问题 - 无法加载 '': 无法将 '' 转换为布尔类型 (选项 '')" @@ -121,7 +121,8 @@ warning.config.image.invalid_hex_value: "在文件 发现问题 warning.config.recipe.duplicate: "在文件 发现问题 - 重复的配方 '' 请检查其他文件中是否存在相同配置" warning.config.recipe.missing_type: "在文件 发现问题 - 配方 '' 缺少必需的 'type' 参数" warning.config.recipe.invalid_type: "在文件 发现问题 - 配方 '' 使用了无效的配方类型 ''" -warning.config.recipe.invalid_item: "在文件 发现问题 - 配方 '' 使用了无效的物品 ''" +warning.config.recipe.invalid_ingredient: "在文件 发现问题 - 配方 '' 使用了无效的原料 ''" +warning.config.recipe.invalid_result: "在文件 发现问题 - 配方 '' 使用了无效的结果 ''" warning.config.recipe.missing_ingredient: "在文件 发现问题 - 烧炼配方 '' 缺少必需的 'ingredient' 参数" warning.config.recipe.missing_result: "在文件 发现问题 - 配方 '' 缺少必需的 'result' 参数" warning.config.recipe.result.missing_id: "在文件 发现问题 - 配方 '' 的结果缺少必需的 'id' 参数" @@ -134,11 +135,17 @@ warning.config.recipe.smithing_transform.post_processor.missing_type: " warning.config.recipe.smithing_transform.post_processor.invalid_type: "在文件 发现问题 - 锻造升级配方 '' 使用了无效的后处理器类型 ''" warning.config.recipe.smithing_transform.post_processor.keep_component.missing_components: "在文件 发现问题 - 锻造升级配方 '' 的 'keep_components' 后处理器缺少必需的 'components' 参数" warning.config.recipe.smithing_transform.post_processor.keep_component.missing_tags: "在文件 发现问题 - 锻造升级配方 '' 的 'keep_tags' 后处理器缺少必需的 'tags' 参数" +warning.config.recipe.smithing_transform.missing_base: "在文件 发现问题 - 锻造升级配方 '' 缺少必需的 'base' 参数" +warning.config.recipe.smithing_trim.missing_base: "在文件 发现问题 - 锻造纹饰配方 '' 缺少必需的 'base' 参数" +warning.config.recipe.smithing_trim.missing_template_type: "在文件 发现问题 - 锻造纹饰配方 '' 缺少必需的 'template-type' 参数" +warning.config.recipe.smithing_trim.missing_addition: "在文件 发现问题 - 锻造纹饰配方 '' 缺少必需的 'addition' 参数" +warning.config.recipe.smithing_trim.missing_pattern: "在文件 发现问题 - 锻造纹饰配方 '' 缺少必需的 'pattern' 参数" 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.missing_value: "在文件 发现问题 - 配置 '' 缺少了 '' 必要的模板参数值. 请使用 arguments 选项进行配置或为此参数设定默认值." warning.config.vanilla_loot.missing_type: "在文件 发现问题 - 原版战利品 '' 缺少必需的 'type' 参数" warning.config.vanilla_loot.invalid_type: "在文件 发现问题 - 原版战利品 '' 使用了无效类型 '' 允许的类型: []" warning.config.vanilla_loot.block.invalid_target: "在文件 发现问题 - 原版战利品 '' 中存在无效的方块目标 ''" @@ -156,13 +163,21 @@ warning.config.furniture.hitbox.custom.invalid_entity: "在文件 在文件 发现问题 - 重复的物品 '' 请检查其他文件中是否存在相同配置" warning.config.item.settings.unknown: "在文件 发现问题 - 物品 '' 使用了未知的设置类型 ''" warning.config.item.settings.invulnerable.invalid_damage_source: "在文件 发现问题 - 物品 '' 物品使用了未知的伤害来源类型 '' 允许的来源: []" -warning.config.item.settings.equippable.missing_slot: "在文件 发现问题 - 物品 '' 缺少了 'equippable' 设置所需的 'slot' 参数." +warning.config.item.settings.equipment.missing_asset_id: "在文件 发现问题 - 物品 '' 缺少 'equipment' 设置所需的 'asset-id' 参数." +warning.config.item.settings.equipment.invalid_asset_id: "在文件 发现问题 - 物品 '' 为 'equipment' 设置配置了无效的 'asset-id'. 这可能是因为你没有创建装备配置或是错误地拼写了 asset-id." +warning.config.item.settings.projectile.missing_item: "在文件 发现问题 - 物品 '' 缺少 'projectile' 设置所需的 'item' 参数." +warning.config.item.data.attribute_modifiers.missing_type: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 数据所需的 'type' 参数." +warning.config.item.data.attribute_modifiers.missing_amount: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 数据所需的 'amount' 参数." +warning.config.item.data.attribute_modifiers.missing_operation: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 数据所需的 'operation' 参数." +warning.config.item.data.attribute_modifiers.display.missing_type: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 显示数据所需的 'type' 参数。" +warning.config.item.data.attribute_modifiers.display.missing_value: "在文件 发现问题 - 物品 '' 缺少 'attribute-modifiers' 显示数据所需的 'value' 参数。" 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.item_model.conflict: "在文件 发现问题 - 物品 '' 使用了无效的 'item-model' 选项. 这个 item-model 已经存在对应的原版物品." 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' 参数" @@ -274,6 +289,7 @@ warning.config.block.behavior.stairs.missing_half: "在文件 warning.config.block.behavior.stairs.missing_shape: "在文件 发现问题 - 方块 '' 的 'stairs_block' 行为缺少必需的 'shape' 属性" warning.config.block.behavior.pressure_plate.missing_powered: "在文件 发现问题 - 方块 '' 的 'pressure_plate_block' 行为缺少必需的 'powered' 属性" warning.config.block.behavior.grass.missing_feature: "在文件 发现问题 - 方块 '' 的 'grass_block' 行为缺少必需的 'feature' 参数" +warning.config.block.behavior.double.missing_half: "在文件 发现问题 - 方块 '' 的 'double_block' 行为缺少必需的 'half' 属性" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" @@ -302,7 +318,7 @@ warning.config.loot_table.entry.item.missing_item: "在文件 warning.config.loot_table.condition.missing_type: "在文件 发现问题 - '' 的战利品表配置错误 某个条件缺少必需的 'type' 参数" warning.config.loot_table.condition.invalid_type: "在文件 发现问题 - '' 的战利品表配置错误 某个条件使用了无效的条件类型 ''" warning.config.host.missing_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 缺少必需的 'type' 参数" -warning.config.host.invalid_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 无效的托管类型 '' 请参考 https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host" +warning.config.host.invalid_type: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 无效的托管类型 '' 请参考 https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host" warning.config.host.external.missing_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 外部托管缺少必需的 'url' 参数" warning.config.host.alist.missing_api_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - Alist 托管缺少必需的 'api-url' 参数" warning.config.host.alist.missing_username: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - Alist 托管缺少必需的 'username' 参数或环境变量 'CE_ALIST_USERNAME'" @@ -378,14 +394,18 @@ warning.config.function.remove_cooldown.missing_id: "在文件 warning.config.selector.missing_type: "在文件 中发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" 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: "无法生成模型,因为模型文件 '' 已存在" warning.config.resource_pack.generation.missing_font_texture: "字体''缺少必要纹理: ''" warning.config.resource_pack.generation.missing_model_texture: "模型''缺少纹理''" warning.config.resource_pack.generation.texture_not_in_atlas: "纹理''不在图集内. 你需要将纹理路径或文件夹前缀添加到图集内,或者启用 config.yml 中的 'obfuscation' 选项" warning.config.resource_pack.generation.missing_item_model: "物品''缺少模型文件: ''" -warning.config.resource_pack.generation.missing_block_model: "方块''缺少模型文件: ''" +warning.config.resource_pack.generation.missing_block_model: "方块状态''缺少模型文件: ''" warning.config.resource_pack.generation.missing_parent_model: "模型''找不到父级模型文件: ''" warning.config.resource_pack.generation.malformatted_json: "Json文件 '' 格式错误." -warning.config.resource_pack.invalid_overlay_format: "在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的overlay格式 ''. Overlay格式必须包含占位符 '{version}'." \ No newline at end of file +warning.config.resource_pack.generation.missing_equipment_texture: "装备 '' 缺少纹理 ''" +warning.config.resource_pack.invalid_overlay_format: "在 config.yml 的 'resource-pack.overlay-format' 处发现问题 - 无效的overlay格式 ''. Overlay格式必须包含占位符 '{version}'." +warning.config.equipment.duplicate: "在文件 发现问题 - 重复的装备配置 ''。请检查其他文件中是否存在相同配置" +warning.config.equipment.missing_type: "在文件 发现问题 - 装备 '' 缺少必需的 'type' 参数" +warning.config.equipment.invalid_type: "在文件 发现问题 - 装备 '' 使用了无效的 'type' 参数" +warning.config.equipment.invalid_sacrificed_armor: "在 config.yml 的 'equipment.sacrificed-vanilla-armor' 处发现问题 - 无效的原版盔甲类型 ''" \ No newline at end of file diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 61abe7288..d41f1c2f1 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -21,11 +21,10 @@ dependencies { 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.2") + implementation("net.momirealms:craft-engine-s3:0.4") // Util compileOnly("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}") // Adventure - // TODO Create an API module compileOnly("net.kyori:adventure-api:${rootProject.properties["adventure_bundle_version"]}") compileOnly("net.kyori:adventure-text-minimessage:${rootProject.properties["adventure_bundle_version"]}") compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}") { @@ -64,6 +63,8 @@ dependencies { compileOnly("com.google.jimfs:jimfs:${rootProject.properties["jimfs_version"]}") // Brigadier compileOnly("com.mojang:brigadier:${rootProject.properties["mojang_brigadier_version"]}") + // authlib + compileOnly("com.mojang:authlib:${rootProject.properties["authlib_version"]}") } java { @@ -97,6 +98,7 @@ tasks { relocate("com.ezylang.evalex", "net.momirealms.craftengine.libraries.evalex") relocate("com.google.common.jimfs", "net.momirealms.craftengine.libraries.jimfs") relocate("org.apache.commons", "net.momirealms.craftengine.libraries.commons") + relocate("io.leangen.geantyref", "net.momirealms.craftengine.libraries.geantyref") } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/advancement/AdvancementType.java b/core/src/main/java/net/momirealms/craftengine/core/advancement/AdvancementType.java new file mode 100644 index 000000000..b1038933f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/advancement/AdvancementType.java @@ -0,0 +1,23 @@ +package net.momirealms.craftengine.core.advancement; + +public enum AdvancementType { + TASK("task"), + CHALLENGE("challenge"), + GOAL("goal"),; + + private final String id; + + AdvancementType(String id) { + this.id = id; + } + + public String id() { + return id; + } + + public static final AdvancementType[] VALUES = values(); + + public static AdvancementType byId(int id) { + return VALUES[id]; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/advancement/network/Advancement.java b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/Advancement.java new file mode 100644 index 000000000..c58194ae9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/Advancement.java @@ -0,0 +1,67 @@ +package net.momirealms.craftengine.core.advancement.network; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Map; +import java.util.Optional; + +public class Advancement { + private final Optional parent; + private final Optional displayInfo; + + // 1.20-1.20.1 + private final Map criteria; + + private final AdvancementRequirements requirements; + private final boolean sendsTelemetryEvent; + + public Advancement(Optional parent, Optional displayInfo, AdvancementRequirements requirements, boolean sendsTelemetryEvent) { + this.criteria = null; + this.displayInfo = displayInfo; + this.parent = parent; + this.requirements = requirements; + this.sendsTelemetryEvent = sendsTelemetryEvent; + } + + @ApiStatus.Obsolete + public Advancement(Optional parent, Optional displayInfo, Map criteria, AdvancementRequirements requirements, boolean sendsTelemetryEvent) { + this.criteria = criteria; + this.displayInfo = displayInfo; + this.parent = parent; + this.requirements = requirements; + this.sendsTelemetryEvent = sendsTelemetryEvent; + } + + public static Advancement read(FriendlyByteBuf buf) { + Optional parent = buf.readOptional(FriendlyByteBuf::readKey); + Optional displayInfo = buf.readOptional(byteBuf -> AdvancementDisplay.read(buf)); + if (VersionHelper.isOrAbove1_20_2()) { + AdvancementRequirements requirements = AdvancementRequirements.read(buf); + boolean sendsTelemetryEvent = buf.readBoolean(); + return new Advancement(parent, displayInfo, requirements, sendsTelemetryEvent); + } else { + Map criteria = buf.readMap(FriendlyByteBuf::readUtf, (byteBuf -> null)); + AdvancementRequirements requirements = AdvancementRequirements.read(buf); + boolean sendsTelemetryEvent = buf.readBoolean(); + return new Advancement(parent, displayInfo, criteria, requirements, sendsTelemetryEvent); + } + } + + public void write(FriendlyByteBuf buf) { + buf.writeOptional(this.parent, FriendlyByteBuf::writeKey); + buf.writeOptional(this.displayInfo, (byteBuf, info) -> info.write(buf)); + if (!VersionHelper.isOrAbove1_20_2()) { + buf.writeMap(this.criteria, FriendlyByteBuf::writeUtf, ((byteBuf, unused) -> {})); + } + this.requirements.write(buf); + buf.writeBoolean(this.sendsTelemetryEvent); + } + + public void applyClientboundData(Player player) { + this.displayInfo.ifPresent(info -> info.applyClientboundData(player)); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementDisplay.java new file mode 100644 index 000000000..93924daf9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementDisplay.java @@ -0,0 +1,115 @@ +package net.momirealms.craftengine.core.advancement.network; + +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.advancement.AdvancementType; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.Tag; + +import java.util.Map; +import java.util.Optional; + +public class AdvancementDisplay { + public static final int FLAG_BACKGROUND = 0b001; + public static final int FLAG_SHOW_TOAST = 0b010; + public static final int FLAG_HIDDEN = 0b100; + private Component title; + private Component description; + private Item icon; + private Optional background; + private final AdvancementType type; + private final boolean showToast; + private final boolean hidden; + private float x; + private float y; + + public AdvancementDisplay(Component title, + Component description, + Item icon, + Optional background, + AdvancementType type, + boolean showToast, + boolean hidden, + float x, + float y) { + this.type = type; + this.showToast = showToast; + this.hidden = hidden; + this.background = background; + this.description = description; + this.icon = icon; + this.title = title; + this.x = x; + this.y = y; + } + + public void applyClientboundData(Player player) { + this.icon = CraftEngine.instance().itemManager().s2c(this.icon, player); + } + + public void write(FriendlyByteBuf buf) { + buf.writeComponent(this.title); + buf.writeComponent(this.description); + CraftEngine.instance().itemManager().encode(buf, this.icon); + buf.writeVarInt(this.type.ordinal()); + int flags = 0; + if (this.background.isPresent()) { + flags |= FLAG_BACKGROUND; + } + if (this.showToast) { + flags |= FLAG_SHOW_TOAST; + } + if (this.hidden) { + flags |= FLAG_HIDDEN; + } + buf.writeInt(flags); + this.background.ifPresent(buf::writeKey); + buf.writeFloat(this.x); + buf.writeFloat(this.y); + } + + public static AdvancementDisplay read(FriendlyByteBuf buf) { + Component title = readComponent(buf); + Component description = readComponent(buf); + Item icon = CraftEngine.instance().itemManager().decode(buf); + AdvancementType type = AdvancementType.byId(buf.readVarInt()); + int flags = buf.readInt(); + boolean hasBackground = (flags & 1) != 0; + Optional background = hasBackground ? Optional.of(buf.readKey()) : Optional.empty(); + boolean showToast = (flags & 2) != 0; + boolean hidden = (flags & 4) != 0; + float x = buf.readFloat(); + float y = buf.readFloat(); + return new AdvancementDisplay(title, description, icon, background, type, showToast, hidden, x, y); + } + + private static Component readComponent(FriendlyByteBuf buf) { + if (Config.interceptAdvancement()) { + if (VersionHelper.isOrAbove1_20_3()) { + Tag nbt = buf.readNbt(false); + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + Component component = AdventureHelper.nbtToComponent(nbt); + if (!tokens.isEmpty()) { + component = AdventureHelper.replaceText(component, tokens); + } + return component; + } else { + String json = buf.readUtf(); + Component component = AdventureHelper.jsonToComponent(json); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (!tokens.isEmpty()) { + component = AdventureHelper.replaceText(component, tokens); + } + return component; + } + } else { + return buf.readComponent(); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementHolder.java b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementHolder.java new file mode 100644 index 000000000..9e4ed5d7e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementHolder.java @@ -0,0 +1,23 @@ +package net.momirealms.craftengine.core.advancement.network; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; + +public record AdvancementHolder(Key id, Advancement advancement) { + + public static AdvancementHolder read(FriendlyByteBuf buf) { + Key key = buf.readKey(); + Advancement ad = Advancement.read(buf); + return new AdvancementHolder(key, ad); + } + + public void write(FriendlyByteBuf buf) { + buf.writeKey(this.id); + this.advancement.write(buf); + } + + public void applyClientboundData(Player player) { + this.advancement.applyClientboundData(player); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementProgress.java b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementProgress.java new file mode 100644 index 000000000..9024a496b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementProgress.java @@ -0,0 +1,27 @@ +package net.momirealms.craftengine.core.advancement.network; + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.HashMap; +import java.util.Map; + +public class AdvancementProgress { + private final Map progress; + + public AdvancementProgress(Map progress) { + this.progress = progress; + } + + public AdvancementProgress() { + this.progress = new HashMap<>(); + } + + public void write(FriendlyByteBuf buf) { + buf.writeMap(this.progress, FriendlyByteBuf::writeUtf, ((byteBuf, criterionProgress) -> criterionProgress.write(buf))); + } + + public static AdvancementProgress read(FriendlyByteBuf buf) { + Map progress = buf.readMap(FriendlyByteBuf::readUtf, CriterionProgress::read); + return new AdvancementProgress(progress); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementRequirements.java b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementRequirements.java new file mode 100644 index 000000000..f3eb80037 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/AdvancementRequirements.java @@ -0,0 +1,23 @@ +package net.momirealms.craftengine.core.advancement.network; + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.ArrayList; +import java.util.List; + +public class AdvancementRequirements { + public static final AdvancementRequirements EMPTY = new AdvancementRequirements(List.of()); + private final List> requirements; + + public AdvancementRequirements(List> requirements) { + this.requirements = requirements; + } + + public void write(FriendlyByteBuf byteBuf) { + byteBuf.writeCollection(this.requirements, ((buf, strings) -> buf.writeCollection(strings, FriendlyByteBuf::writeUtf))); + } + + public static AdvancementRequirements read(FriendlyByteBuf byteBuf) { + return new AdvancementRequirements(byteBuf.readCollection(ArrayList::new, buf -> buf.readCollection(ArrayList::new, FriendlyByteBuf::readUtf))); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/advancement/network/CriterionProgress.java b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/CriterionProgress.java new file mode 100644 index 000000000..87a0456e4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/advancement/network/CriterionProgress.java @@ -0,0 +1,42 @@ +package net.momirealms.craftengine.core.advancement.network; + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.Nullable; + +import java.time.Instant; + +public class CriterionProgress { + @Nullable + private Instant obtainedTimestamp; + + public CriterionProgress() { + } + + public CriterionProgress(@Nullable Instant obtainedTimestamp) { + this.obtainedTimestamp = obtainedTimestamp; + } + + public boolean isDone() { + return this.obtainedTimestamp != null; + } + + public void grant() { + this.obtainedTimestamp = Instant.now(); + } + + public void revoke() { + this.obtainedTimestamp = null; + } + + public @Nullable Instant obtainedTimestamp() { + return obtainedTimestamp; + } + + public void write(FriendlyByteBuf buf) { + buf.writeNullable(this.obtainedTimestamp, FriendlyByteBuf::writeInstant); + } + + public static CriterionProgress read(FriendlyByteBuf buf) { + return new CriterionProgress(buf.readNullable(FriendlyByteBuf::readInstant)); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/attribute/AttributeModifier.java b/core/src/main/java/net/momirealms/craftengine/core/attribute/AttributeModifier.java new file mode 100644 index 000000000..0d5ff2dfb --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/attribute/AttributeModifier.java @@ -0,0 +1,81 @@ +package net.momirealms.craftengine.core.attribute; + +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +public class AttributeModifier { + private final String type; + private final Slot slot; + private final Key id; + private final double amount; + private final Operation operation; + @Nullable + private final Display display; + + public AttributeModifier(String type, Slot slot, Key id, double amount, Operation operation, @Nullable Display display) { + this.amount = amount; + this.display = display; + this.id = id; + this.operation = operation; + this.slot = slot; + this.type = type; + } + + public double amount() { + return amount; + } + + public @Nullable Display display() { + return display; + } + + public Key id() { + return id; + } + + public Operation operation() { + return operation; + } + + public Slot slot() { + return slot; + } + + public String type() { + return type; + } + + public enum Slot { + ANY, + HAND, + ARMOR, + MAINHAND, + OFFHAND, + HEAD, + CHEST, + LEGS, + FEET, + BODY + } + + public enum Operation { + ADD_VALUE("add_value"), ADD_MULTIPLIED_BASE("add_multiplied_base"), ADD_MULTIPLIED_TOTAL("add_multiplied_total"); + + private final String id; + + Operation(String id) { + this.id = id; + } + + public String id() { + return id; + } + } + + public record Display(AttributeModifier.Display.Type type, String value) { + + public enum Type { + DEFAULT, HIDDEN, OVERRIDE + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/attribute/Attributes.java b/core/src/main/java/net/momirealms/craftengine/core/attribute/Attributes.java new file mode 100644 index 000000000..2ff402e78 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/attribute/Attributes.java @@ -0,0 +1,43 @@ +package net.momirealms.craftengine.core.attribute; + +import net.momirealms.craftengine.core.util.Key; + +public final class Attributes { + private Attributes() {} + // latest version + public static final Key ARMOR = Key.from("armor"); + public static final Key ARMOR_TOUGHNESS = Key.from("armor_toughness"); + public static final Key ATTACK_DAMAGE = Key.from("attack_damage"); + public static final Key ATTACK_KNOCKBACK = Key.from("attack_knockback"); + public static final Key ATTACK_SPEED = Key.from("attack_speed"); + public static final Key BLOCK_BREAK_SPEED = Key.from("block_break_speed"); + public static final Key BLOCK_INTERACTION_RANGE = Key.from("block_interaction_range"); + public static final Key BURNING_TIME = Key.from("burning_time"); + public static final Key CAMERA_DISTANCE = Key.from("camera_distance"); + public static final Key ENTITY_INTERACTION_RANGE = Key.from("entity_interaction_range"); + public static final Key EXPLOSION_KNOCKBACK_RESISTANCE = Key.from("explosion_knockback_resistance"); + public static final Key FALL_DAMAGE_MULTIPLIER = Key.from("fall_damage_multiplier"); + public static final Key FLYING_SPEED = Key.from("flying_speed"); + public static final Key FOLLOW_RANGE = Key.from("follow_range"); + public static final Key GRAVITY = Key.from("gravity"); + public static final Key JUMP_STRENGTH = Key.from("jump_strength"); + public static final Key KNOCKBACK_RESISTANCE = Key.from("knockback_resistance"); + public static final Key LUCK = Key.from("luck"); + public static final Key MAX_ABSORPTION = Key.from("max_absorption"); + public static final Key MAX_HEALTH = Key.from("max_health"); + public static final Key MINING_EFFICIENCY = Key.from("mining_efficiency"); + public static final Key MOVEMENT_EFFICIENCY = Key.from("movement_efficiency"); + public static final Key MOVEMENT_SPEED = Key.from("movement_speed"); + public static final Key OXYGEN_BONUS = Key.from("oxygen_bonus"); + public static final Key SAFE_FALL_DISTANCE = Key.from("safe_fall_distance"); + public static final Key SCALE = Key.from("scale"); + public static final Key SPAWN_REINFORCEMENT = Key.from("spawn_reinforcements"); + public static final Key SNEAKING_SPEED = Key.from("sneaking_speed"); + public static final Key STEP_HEIGHT = Key.from("step_height"); + public static final Key SUBMERGED_MINING_SPEED = Key.from("submerged_mining_speed"); + public static final Key SWEEPING_DAMAGE_RATIO = Key.from("sweeping_damage_ratio"); + public static final Key TEMPT_RANGE = Key.from("tempt_range"); + public static final Key WATER_MOVEMENT_EFFICIENCY = Key.from("water_movement_efficiency"); + public static final Key WAYPOINT_RECEIVE_RANGE = Key.from("waypoint_receive_range"); + public static final Key WAYPOINT_TRANSMIT_RANGE = Key.from("waypoint_transmit_range"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/attribute/Attributes1_21.java b/core/src/main/java/net/momirealms/craftengine/core/attribute/Attributes1_21.java new file mode 100644 index 000000000..0410b3922 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/attribute/Attributes1_21.java @@ -0,0 +1,37 @@ +package net.momirealms.craftengine.core.attribute; + +import net.momirealms.craftengine.core.util.Key; + +public final class Attributes1_21 { + private Attributes1_21() {} + public static final Key ARMOR = Key.from("generic.armor"); + public static final Key ARMOR_TOUGHNESS = Key.from("generic.armor_toughness"); + public static final Key ATTACK_DAMAGE = Key.from("generic.attack_damage"); + public static final Key ATTACK_KNOCKBACK = Key.from("generic.attack_knockback"); + public static final Key ATTACK_SPEED = Key.from("generic.attack_speed"); + public static final Key FLYING_SPEED = Key.from("generic.flying_speed"); + public static final Key FOLLOW_RANGE = Key.from("generic.follow_range"); + public static final Key KNOCKBACK_RESISTANCE = Key.from("generic.knockback_resistance"); + public static final Key LUCK = Key.from("generic.luck"); + public static final Key MAX_ABSORPTION = Key.from("generic.max_absorption"); + public static final Key MAX_HEALTH = Key.from("generic.max_health"); + public static final Key MOVEMENT_EFFICIENCY = Key.from("generic.movement_efficiency"); + public static final Key SCALE = Key.from("generic.scale"); + public static final Key STEP_HEIGHT = Key.from("generic.step_height"); + public static final Key JUMP_STRENGTH = Key.from("generic.jump_strength"); + public static final Key ENTITY_INTERACTION_RANGE = Key.from("player.entity_interaction_range"); + public static final Key BLOCK_INTERACTION_RANGE = Key.from("player.block_interaction_range"); + public static final Key SPAWN_REINFORCEMENT = Key.from("zombie.spawn_reinforcements"); + public static final Key BLOCK_BREAK_SPEED = Key.from("player.block_break_speed"); + public static final Key GRAVITY = Key.from("generic.gravity"); + public static final Key SAFE_FALL_DISTANCE = Key.from("generic.safe_fall_distance"); + public static final Key FALL_DAMAGE_MULTIPLIER = Key.from("generic.fall_damage_multiplier"); + public static final Key BURNING_TIME = Key.from("generic.burning_time"); + public static final Key EXPLOSION_KNOCKBACK_RESISTANCE = Key.from("generic.explosion_knockback_resistance"); + public static final Key MINING_EFFICIENCY = Key.from("player.mining_efficiency"); + public static final Key OXYGEN_BONUS = Key.from("generic.oxygen_bonus"); + public static final Key SNEAKING_SPEED = Key.from("player.sneaking_speed"); + public static final Key SUBMERGED_MINING_SPEED = Key.from("player.submerged_mining_speed"); + public static final Key SWEEPING_DAMAGE_RATIO = Key.from("player.sweeping_damage_ratio"); + public static final Key WATER_MOVEMENT_EFFICIENCY = Key.from("generic.water_movement_efficiency"); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java index 259a6e37b..4af326d66 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.ApiStatus; import java.util.Optional; import java.util.concurrent.Callable; @@ -33,8 +34,8 @@ public abstract class BlockBehavior { return superMethod.call(); } - // 1.20.1-1.21.1 Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos - // 1.21.2+ LevelReader level, ScheduledTickAccess scheduledTickAccess, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, RandomSource random + // 1.20.1-1.21.1 BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos + // 1.21.2+ BlockState state, LevelReader level, ScheduledTickAccess scheduledTickAccess, BlockPos pos, Direction direction, BlockPos neighborPos, BlockState neighborState, RandomSource random public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { return args[0]; } @@ -94,7 +95,7 @@ public abstract class BlockBehavior { } // 1.21+ BlockState state, ServerLevel level, BlockPos pos, Explosion explosion, BiConsumer dropConsumer - public void onExplosionHit(Object thisBlock, Object[] args, Callable superMethod) { + public void onExplosionHit(Object thisBlock, Object[] args, Callable superMethod) throws Exception { } // LevelAccessor level, BlockPos pos, BlockState state, FluidState fluidState @@ -123,6 +124,11 @@ public abstract class BlockBehavior { public void affectNeighborsAfterRemoval(Object thisBlock, Object[] args, Callable superMethod) throws Exception { } + // 1.20~1.21.4 BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston + @ApiStatus.Obsolete + public void onRemove(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + } + // BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side public int getSignal(Object thisBlock, Object[] args, Callable superMethod) { return 0; @@ -138,6 +144,15 @@ public abstract class BlockBehavior { return false; } + // Level level, BlockPos pos, BlockState state, Player player + public Object playerWillDestroy(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + return superMethod.call(); + } + + // BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience + public void spawnAfterBreak(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + } + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { return state; } 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 d4d5b0b63..fba210d01 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 @@ -107,6 +107,10 @@ public final class BlockKeys { public static final Key PALE_OAK_BUTTON = Key.of("minecraft:pale_oak_button"); public static final Key MANGROVE_BUTTON = Key.of("minecraft:mangrove_button"); public static final Key BAMBOO_BUTTON = Key.of("minecraft:bamboo_button"); + public static final Key CRIMSON_BUTTON = Key.of("minecraft:crimson_button"); + public static final Key WARPED_BUTTON = Key.of("minecraft:warped_button"); + public static final Key STONE_BUTTON = Key.of("minecraft:stone_button"); + public static final Key POLISHED_BLACKSTONE_BUTTON = Key.of("minecraft:polished_blackstone_button"); public static final Key OAK_TRAPDOOR = Key.of("minecraft:oak_trapdoor"); public static final Key SPRUCE_TRAPDOOR = Key.of("minecraft:spruce_trapdoor"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/LazyBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/LazyBlockState.java deleted file mode 100644 index 4e40bf470..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/block/LazyBlockState.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.momirealms.craftengine.core.block; - -import net.momirealms.craftengine.core.plugin.CraftEngine; - -public final class LazyBlockState { - private final String state; - private BlockStateWrapper packedBlockState; - - public LazyBlockState(String state) { - this.state = state; - } - - public BlockStateWrapper getState() { - if (this.packedBlockState == null) { - this.packedBlockState = CraftEngine.instance().blockManager().createPackedBlockState(state); - if (this.packedBlockState == null) { - CraftEngine.instance().logger().warn("Could not create block state: " + this.state); - } - } - return this.packedBlockState; - } -} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java index b346ccf1f..d109bc77d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -18,9 +17,8 @@ public class BlockBehaviors { public static final Key EMPTY = Key.from("craftengine:empty"); public static void register(Key key, BlockBehaviorFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK_BEHAVIOR_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.BLOCK_BEHAVIOR_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.BLOCK_BEHAVIOR_FACTORY) + .register(ResourceKey.create(Registries.BLOCK_BEHAVIOR_FACTORY.location(), key), factory); } public static BlockBehavior fromMap(CustomBlock block, @Nullable Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java index 4edc88ae1..5636e7ae9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Properties.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.block.properties; import net.momirealms.craftengine.core.block.state.properties.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.*; @@ -40,8 +39,7 @@ public class Properties { } public static void register(Key key, PropertyFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.PROPERTY_FACTORY).registerForHolder(new ResourceKey<>(Registries.PROPERTY_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.PROPERTY_FACTORY).register(ResourceKey.create(Registries.PROPERTY_FACTORY.location(), key), factory); } public static Property fromMap(String name, Map map) { 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 a5e2274bc..abc819e6a 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 @@ -90,13 +90,6 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { } EnumMap placements = new EnumMap<>(AnchorType.class); Object placementObj = section.get("placement"); - if (placementObj == null) { - // 防呆 - if (section.containsKey("material")) { - plugin.itemManager().parser().parseSection(pack, path, id, section); - return; - } - } Map placementMap = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(placementObj, "warning.config.furniture.missing_placement"), false); if (placementMap.isEmpty()) { throw new LocalizedResourceConfigException("warning.config.furniture.missing_placement"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java index 3e1876ff4..e610ec044 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureElement.java @@ -3,9 +3,7 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.world.WorldPosition; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java index 520c4ecd3..c7c5704e9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureExtraData.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.logger.Debugger; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.NBT; @@ -39,9 +39,7 @@ public class FurnitureExtraData { try { return Optional.of(CraftEngine.instance().itemManager().fromByteArray(data)); } catch (Exception e) { - if (Config.debug()) { - CraftEngine.instance().logger().warn("Failed to read item data", e); - } + Debugger.FURNITURE.warn(() -> "Failed to read furniture item data", e); return Optional.empty(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java index f77435813..2cb59c4b8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/HitBoxTypes.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -18,9 +17,8 @@ public class HitBoxTypes { public static final Key CUSTOM = Key.of("minecraft:custom"); public static void register(Key key, HitBoxFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.HITBOX_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.HITBOX_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.HITBOX_FACTORY) + .register(ResourceKey.create(Registries.HITBOX_FACTORY.location(), key), factory); } public static HitBox fromMap(Map arguments) { 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 e0b2d0394..073a8d41c 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 @@ -8,7 +8,7 @@ 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 org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -17,7 +17,7 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract boolean isSecondaryUseActive(); - @Nullable + @NotNull public abstract Item getItemInHand(InteractionHand hand); @Override 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 06b87e5b2..db56a096f 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 @@ -1,13 +1,12 @@ package net.momirealms.craftengine.core.item; -import com.google.common.collect.ImmutableMap; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; 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 net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.Collections; @@ -16,19 +15,17 @@ import java.util.Map; import java.util.Optional; public abstract class AbstractCustomItem implements CustomItem { - protected final Holder id; + protected final UniqueKey id; protected final Key material; protected final Key clientBoundMaterial; protected final ItemDataModifier[] modifiers; - protected final Map> modifierMap; protected final ItemDataModifier[] clientBoundModifiers; - protected final Map> clientBoundModifierMap; protected final List behaviors; protected final ItemSettings settings; protected final Map>> events; @SuppressWarnings("unchecked") - public AbstractCustomItem(Holder id, Key material, Key clientBoundMaterial, + public AbstractCustomItem(UniqueKey id, Key material, Key clientBoundMaterial, List behaviors, List> modifiers, List> clientBoundModifiers, @@ -44,14 +41,6 @@ public abstract class AbstractCustomItem implements CustomItem { this.clientBoundModifiers = clientBoundModifiers.toArray(new ItemDataModifier[0]); this.behaviors = List.copyOf(behaviors); this.settings = settings; - ImmutableMap.Builder> modifierMapBuilder = ImmutableMap.builder(); - for (ItemDataModifier modifier : modifiers) { - modifierMapBuilder.put(modifier.name(), modifier); - } - this.modifierMap = modifierMapBuilder.build(); - ImmutableMap.Builder> clientSideModifierMapBuilder = ImmutableMap.builder(); - this.clientBoundModifierMap = clientSideModifierMapBuilder.build(); - } @Override @@ -63,11 +52,11 @@ public abstract class AbstractCustomItem implements CustomItem { @Override public Key id() { - return this.id.value(); + return this.id.key(); } @Override - public Holder idHolder() { + public UniqueKey uniqueId() { return this.id; } @@ -86,11 +75,6 @@ public abstract class AbstractCustomItem implements CustomItem { return this.modifiers; } - @Override - public Map> dataModifierMap() { - return this.modifierMap; - } - @Override public boolean hasClientBoundDataModifier() { return this.clientBoundModifiers.length != 0; @@ -101,11 +85,6 @@ public abstract class AbstractCustomItem implements CustomItem { return this.clientBoundModifiers; } - @Override - public Map> clientBoundDataModifierMap() { - return this.clientBoundModifierMap; - } - @Override public ItemSettings settings() { return this.settings; 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 fc3cc6e25..74f5d96a3 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 @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.item.data.JukeboxPlayable; import net.momirealms.craftengine.core.item.data.Trim; import net.momirealms.craftengine.core.item.setting.EquipmentData; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.UniqueKey; import net.momirealms.sparrow.nbt.Tag; import java.util.List; @@ -23,6 +24,11 @@ public class AbstractItem, I> implements Item { this.item = item; } + @Override + public boolean isEmpty() { + return this.factory.isEmpty(this.item); + } + @Override public Item itemModel(String data) { this.factory.itemModel(this.item, data); @@ -153,6 +159,11 @@ public class AbstractItem, I> implements Item { return this.factory.vanillaId(this.item); } + @Override + public UniqueKey recipeIngredientId() { + return this.factory.recipeIngredientID(this.item); + } + @Override public Optional customId() { return this.factory.customId(this.item); @@ -320,8 +331,13 @@ public class AbstractItem, I> implements Item { } @Override - public Tag getNBTTag(Object... path) { - return this.factory.getNBTTag(this.item, path); + public Tag getTag(Object... path) { + return this.factory.getTag(this.item, path); + } + + @Override + public Object getExactTag(Object... path) { + return this.factory.getExactTag(this.item, path); } @Override @@ -355,6 +371,11 @@ public class AbstractItem, I> implements Item { return this.factory.getExactComponent(this.item, type); } + @Override + public void setExactComponent(Object type, Object value) { + this.factory.setExactComponent(this.item, type, value); + } + @Override public Object getJavaComponent(Object type) { return this.factory.getJavaComponent(this.item, type); @@ -366,7 +387,12 @@ public class AbstractItem, I> implements Item { } @Override - public Tag getNBTComponent(Object type) { + public Tag getSparrowNBTComponent(Object type) { + return this.factory.getSparrowNBTComponent(this.item, type); + } + + @Override + public Object getNBTComponent(Object type) { return this.factory.getNBTComponent(this.item, type); } 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 8452d6334..ae246230c 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 @@ -1,16 +1,19 @@ package net.momirealms.craftengine.core.item; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import net.momirealms.craftengine.core.attribute.AttributeModifier; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviors; import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.data.JukeboxPlayable; +import net.momirealms.craftengine.core.item.equipment.*; import net.momirealms.craftengine.core.item.modifier.*; import net.momirealms.craftengine.core.item.setting.EquipmentData; -import net.momirealms.craftengine.core.item.setting.ItemEquipment; +import net.momirealms.craftengine.core.pack.AbstractPackManager; 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.misc.Equipment; import net.momirealms.craftengine.core.pack.model.*; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; @@ -24,9 +27,6 @@ import net.momirealms.craftengine.core.plugin.context.text.TextProvider; import net.momirealms.craftengine.core.plugin.context.text.TextProviders; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; -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; @@ -41,19 +41,20 @@ import java.util.stream.Stream; public abstract class AbstractItemManager extends AbstractModelGenerator implements ItemManager { protected static final Map> VANILLA_ITEM_EXTRA_BEHAVIORS = new HashMap<>(); protected static final Set VANILLA_ITEMS = new HashSet<>(1024); - protected static final Map>> VANILLA_ITEM_TAGS = new HashMap<>(); + protected static final Map> VANILLA_ITEM_TAGS = new HashMap<>(); private final ItemParser itemParser; + private final EquipmentParser equipmentParser; protected final Map> externalItemProviders = new HashMap<>(); protected final Map>> dataFunctions = new HashMap<>(); protected final Map> customItems = new HashMap<>(); - protected final Map>> customItemTags; - protected final Map> cmdConflictChecker; - protected final Map modernItemModels1_21_4; - protected final Map> modernItemModels1_21_2; - protected final Map> legacyOverrides; - protected final Map> modernOverrides; - protected final Map equipmentsToGenerate; + protected final Map> customItemTags = new HashMap<>(); + protected final Map> cmdConflictChecker = new HashMap<>(); + protected final Map modernItemModels1_21_4 = new HashMap<>(); + protected final Map> modernItemModels1_21_2 = new HashMap<>(); + protected final Map> legacyOverrides = new HashMap<>(); + protected final Map> modernOverrides = new HashMap<>(); + protected final Map equipments = new HashMap<>(); // Cached command suggestions protected final List cachedSuggestions = new ArrayList<>(); protected final List cachedTotemSuggestions = new ArrayList<>(); @@ -61,20 +62,14 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected AbstractItemManager(CraftEngine plugin) { super(plugin); this.itemParser = new ItemParser(); + this.equipmentParser = new EquipmentParser(); this.registerFunctions(); - this.legacyOverrides = new HashMap<>(); - this.modernOverrides = new HashMap<>(); - this.customItemTags = new HashMap<>(); - this.cmdConflictChecker = new HashMap<>(); - this.modernItemModels1_21_4 = new HashMap<>(); - this.modernItemModels1_21_2 = new HashMap<>(); - this.equipmentsToGenerate = new HashMap<>(); } @Override public void registerDataType(Function> factory, String... alias) { for (String a : alias) { - dataFunctions.put(a, factory); + this.dataFunctions.put(a, factory); } } @@ -87,11 +82,11 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected void applyDataFunctions(Map dataSection, Consumer> consumer) { if (dataSection != null) { for (Map.Entry dataEntry : dataSection.entrySet()) { - Optional.ofNullable(dataFunctions.get(dataEntry.getKey())).ifPresent(function -> { + Optional.ofNullable(this.dataFunctions.get(dataEntry.getKey())).ifPresent(function -> { try { consumer.accept(function.apply(dataEntry.getValue())); } catch (IllegalArgumentException e) { - plugin.logger().warn("Invalid data format", e); + this.plugin.logger().warn("Invalid data format", e); } }); } @@ -99,8 +94,8 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } @Override - public ConfigParser parser() { - return this.itemParser; + public ConfigParser[] parsers() { + return new ConfigParser[]{this.itemParser, this.equipmentParser}; } @Override @@ -124,12 +119,22 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl this.legacyOverrides.clear(); this.modernOverrides.clear(); this.customItemTags.clear(); - this.equipmentsToGenerate.clear(); + this.equipments.clear(); this.cmdConflictChecker.clear(); this.modernItemModels1_21_4.clear(); this.modernItemModels1_21_2.clear(); } + @Override + public Map equipments() { + return Collections.unmodifiableMap(this.equipments); + } + + @Override + public Optional getEquipment(Key key) { + return Optional.ofNullable(this.equipments.get(key)); + } + @Override public Optional> getCustomItem(Key key) { return Optional.ofNullable(this.customItems.get(key)); @@ -151,26 +156,19 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // tags Set tags = customItem.settings().tags(); for (Key tag : tags) { - this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(customItem.idHolder()); - } - // equipment generation - ItemEquipment equipment = customItem.settings().equipment(); - if (equipment != null) { - EquipmentData data = equipment.data(); - Equipment equipmentJson = this.equipmentsToGenerate.computeIfAbsent(data.assetId(), k -> new Equipment()); - equipmentJson.addAll(equipment); + this.customItemTags.computeIfAbsent(tag, k -> new ArrayList<>()).add(customItem.uniqueId()); } return true; } @Override - public List> tagToItems(Key tag) { - List> items = new ArrayList<>(); - List> holders = VANILLA_ITEM_TAGS.get(tag); + public List tagToItems(Key tag) { + List items = new ArrayList<>(); + List holders = VANILLA_ITEM_TAGS.get(tag); if (holders != null) { items.addAll(holders); } - List> customItems = this.customItemTags.get(tag); + List customItems = this.customItemTags.get(tag); if (customItems != null) { items.addAll(customItems); } @@ -178,12 +176,12 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } @Override - public List> tagToVanillaItems(Key tag) { + public List tagToVanillaItems(Key tag) { return Collections.unmodifiableList(VANILLA_ITEM_TAGS.getOrDefault(tag, List.of())); } @Override - public List> tagToCustomItems(Key tag) { + public List tagToCustomItems(Key tag) { return Collections.unmodifiableList(this.customItemTags.getOrDefault(tag, List.of())); } @@ -249,17 +247,57 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return Collections.unmodifiableMap(this.modernOverrides); } - @Override - public Map equipmentsToGenerate() { - return Collections.unmodifiableMap(this.equipmentsToGenerate); - } - @Override public boolean isVanillaItem(Key item) { return VANILLA_ITEMS.contains(item); } - protected abstract CustomItem.Builder createPlatformItemBuilder(Holder id, Key material, Key clientBoundMaterial); + protected abstract CustomItem.Builder createPlatformItemBuilder(UniqueKey id, Key material, Key clientBoundMaterial); + + protected abstract void registerArmorTrimPattern(Collection equipments); + + public class EquipmentParser implements ConfigParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"equipments", "equipment"}; + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public int loadingSequence() { + return LoadingSequence.EQUIPMENT; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + if (AbstractItemManager.this.equipments.containsKey(id)) { + throw new LocalizedResourceConfigException("warning.config.equipment.duplicate"); + } + Equipment equipment = Equipments.fromMap(id, section); + AbstractItemManager.this.equipments.put(id, equipment); + } + + @Override + public void postProcess() { + List trims = AbstractItemManager.this.equipments.values().stream() + .filter(TrimBasedEquipment.class::isInstance) + .map(Equipment::assetId) + .toList(); + registerArmorTrimPattern(trims); + } + } + + public void addOrMergeEquipment(ComponentBasedEquipment equipment) { + Equipment previous = this.equipments.get(equipment.assetId()); + if (previous instanceof ComponentBasedEquipment another) { + for (Map.Entry> entry : equipment.layers().entrySet()) { + another.addLayer(entry.getKey(), entry.getValue()); + } + } else { + this.equipments.put(equipment.assetId(), equipment); + } + } public class ItemParser implements ConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; @@ -288,15 +326,14 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl throw new LocalizedResourceConfigException("warning.config.item.duplicate"); } - // register for recipes - Holder.Reference holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(id) - .orElseGet(() -> ((WritableRegistry) BuiltInRegistries.OPTIMIZED_ITEM_ID) - .register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), id), id)); - + UniqueKey uniqueId = UniqueKey.create(id); + // 判断是不是原版物品 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"); + // 如果是原版物品,那么custom-model-data只能是0,即使用户设置了其他值 + int customModelData = isVanillaItem ? 0 : ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data"); + boolean clientBoundModel = section.containsKey("client-bound-model") ? ResourceConfigUtils.getAsBoolean(section.get("client-bound-data"), "client-bound-data") : Config.globalClientboundModel(); if (customModelData < 0) { throw new LocalizedResourceConfigException("warning.config.item.invalid_custom_model_data", String.valueOf(customModelData)); } @@ -304,41 +341,46 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); } + // item-model值 Key itemModelKey = null; - CustomItem.Builder itemBuilder = createPlatformItemBuilder(holder, material, clientBoundMaterial); + CustomItem.Builder itemBuilder = createPlatformItemBuilder(uniqueId, material, clientBoundMaterial); boolean hasItemModelSection = section.containsKey("item-model"); - // To get at least one model provider - // Sets some basic model info + // 如果custom-model-data不为0 if (customModelData > 0) { - itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); + if (clientBoundModel) itemBuilder.clientBoundDataModifier(new CustomModelDataModifier<>(customModelData)); + else itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); } - // Requires the item to have model before apply item-model + // 如果没有item-model选项被配置,同时这个物品又含有 model 区域 else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isOrAbove1_21_2()) { - // check server version here because components require 1.21.2+ - // customize or use the id + // 那么使用物品id当成item-model的值 itemModelKey = Key.from(section.getOrDefault("item-model", id.toString()).toString()); + // 但是有个前提,id必须是有效的resource location if (ResourceLocation.isValid(itemModelKey.toString())) { - itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); + if (clientBoundModel) itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModelKey)); + else itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); } else { itemModelKey = null; } } + // 如果有item-model if (hasItemModelSection && VersionHelper.isOrAbove1_21_2()) { itemModelKey = Key.from(section.get("item-model").toString()); - itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); + if (clientBoundModel) itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModelKey)); + else itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); } - // Get item data + // 应用物品数据 applyDataFunctions(MiscUtils.castToMap(section.get("data"), true), itemBuilder::dataModifier); applyDataFunctions(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); - // Add custom it here to make sure that id is always applied + // 如果不是原版物品,那么加入ce的标识符 if (!isVanillaItem) itemBuilder.dataModifier(new IdModifier<>(id)); + // 构建自定义物品 CustomItem customItem = itemBuilder .behaviors(ItemBehaviors.fromObj(pack, path, id, ResourceConfigUtils.get(section, "behavior", "behaviors"))) .settings(Optional.ofNullable(ResourceConfigUtils.get(section, "settings")) @@ -347,27 +389,32 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl .orElse(ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem))) .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) .build(); - + // 添加到缓存 addCustomItem(customItem); - // add it to category + // 如果有类别,则添加 if (section.containsKey("category")) { AbstractItemManager.this.plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); } - // model part, can be null - // but if it exists, either custom model data or item model should be configured + // 模型配置区域,如果这里被配置了,那么用户必须要配置custom-model-data或item-model Map modelSection = MiscUtils.castToMap(section.get("model"), true); Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); if (modelSection == null && legacyModelSection == null) { return; } - // 如果设置了model,但是没有模型值? - if (customModelData == 0 && itemModelKey == null) { - throw new LocalizedResourceConfigException("warning.config.item.missing_model_id"); + + boolean needsModelSection = isModernFormatRequired() || (needsLegacyCompatibility() && legacyModelSection == null); + // 只对自定义物品有这个限制 + if (!isVanillaItem) { + // 既没有模型值也没有item-model + if (customModelData == 0 && itemModelKey == null) { + throw new LocalizedResourceConfigException("warning.config.item.missing_model_id"); + } } - // 1.21.4+必须要配置model区域 - if (isModernFormatRequired() && modelSection == null) { + + // 1.21.4+必须要配置model区域,如果不需要高版本兼容,则可以只写legacy-model + if (needsModelSection && modelSection == null) { throw new LocalizedResourceConfigException("warning.config.item.missing_model"); } @@ -375,13 +422,14 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl ItemModel modernModel = null; // 旧版格式 TreeSet legacyOverridesModels = null; - - if (isModernFormatRequired() || (needsLegacyCompatibility() && legacyModelSection == null)) { + // 如果需要支持新版item model 或者用户需要旧版本兼容,但是没配置legacy-model + if (needsModelSection) { modernModel = ItemModels.fromMap(modelSection); for (ModelGeneration generation : modernModel.modelsToGenerate()) { prepareModelGeneration(generation); } } + // 如果需要旧版本兼容 if (needsLegacyCompatibility()) { if (legacyModelSection != null) { LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection, customModelData); @@ -398,43 +446,61 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } - // use custom model data - if (customModelData != 0) { - // use custom model data - // check conflict - 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()); + // 自定义物品的model处理 + if (!isVanillaItem) { + // 这个item-model是否存在,且是原版item-model + boolean isVanillaItemModel = itemModelKey != null && AbstractPackManager.PRESET_ITEMS.containsKey(itemModelKey); + // 使用了自定义模型值 + if (customModelData != 0) { + // 如果用户主动设置了item-model且为原版物品,则使用item-model为基础模型,否则使用其视觉材质对应的item-model + Key finalBaseModel = isVanillaItemModel ? itemModelKey : clientBoundMaterial; + // 检查cmd冲突 + Map conflict = AbstractItemManager.this.cmdConflictChecker.computeIfAbsent(finalBaseModel, 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); + // 添加新版item model + if (isModernFormatRequired() && modernModel != null) { + TreeMap map = AbstractItemManager.this.modernOverrides.computeIfAbsent(finalBaseModel, k -> new TreeMap<>()); + map.put(customModelData, new ModernItemModel( + modernModel, + ResourceConfigUtils.getAsBoolean(section.getOrDefault("oversized-in-gui", true), "oversized-in-gui"), + ResourceConfigUtils.getAsBoolean(section.getOrDefault("hand-animation-on-swap", true), "hand-animation-on-swap") + )); + } + // 添加旧版 overrides + if (needsLegacyCompatibility() && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { + TreeSet lom = AbstractItemManager.this.legacyOverrides.computeIfAbsent(finalBaseModel, k -> new TreeSet<>()); + lom.addAll(legacyOverridesModels); + } + } else if (isVanillaItemModel) { + throw new LocalizedResourceConfigException("warning.config.item.item_model.conflict", itemModelKey.asString()); } - conflict.put(customModelData, id); - // Parse models - if (isModernFormatRequired() && modernModel != null) { - TreeMap map = AbstractItemManager.this.modernOverrides.computeIfAbsent(clientBoundMaterial, k -> new TreeMap<>()); - map.put(customModelData, new ModernItemModel( - modernModel, - ResourceConfigUtils.getAsBoolean(section.getOrDefault("oversized-in-gui", true), "oversized-in-gui"), - ResourceConfigUtils.getAsBoolean(section.getOrDefault("hand-animation-on-swap", true), "hand-animation-on-swap") - )); - } - if (needsLegacyCompatibility() && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { - TreeSet lom = AbstractItemManager.this.legacyOverrides.computeIfAbsent(clientBoundMaterial, k -> new TreeSet<>()); - lom.addAll(legacyOverridesModels); - } - } - // use item model - if (itemModelKey != null) { - if (isModernFormatRequired() && modernModel != null) { - AbstractItemManager.this.modernItemModels1_21_4.put(itemModelKey, new ModernItemModel( + // 使用了item-model组件,且不是原版物品的 + if (itemModelKey != null && !isVanillaItemModel) { + if (isModernFormatRequired() && modernModel != null) { + AbstractItemManager.this.modernItemModels1_21_4.put(itemModelKey, new ModernItemModel( + modernModel, + ResourceConfigUtils.getAsBoolean(section.getOrDefault("oversized-in-gui", true), "oversized-in-gui"), + ResourceConfigUtils.getAsBoolean(section.getOrDefault("hand-animation-on-swap", true), "hand-animation-on-swap") + )); + } + if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2) && needsLegacyCompatibility() && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { + TreeSet lom = AbstractItemManager.this.modernItemModels1_21_2.computeIfAbsent(itemModelKey, k -> new TreeSet<>()); + lom.addAll(legacyOverridesModels); + } + } + } else { + // 原版物品的item model覆写 + if (isModernFormatRequired()) { + AbstractItemManager.this.modernItemModels1_21_4.put(id, new ModernItemModel( modernModel, ResourceConfigUtils.getAsBoolean(section.getOrDefault("oversized-in-gui", true), "oversized-in-gui"), ResourceConfigUtils.getAsBoolean(section.getOrDefault("hand-animation-on-swap", true), "hand-animation-on-swap") )); } - if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2) && needsLegacyCompatibility() && legacyOverridesModels != null && !legacyOverridesModels.isEmpty()) { - TreeSet lom = AbstractItemManager.this.modernItemModels1_21_2.computeIfAbsent(itemModelKey, k -> new TreeSet<>()); - lom.addAll(legacyOverridesModels); - } } } } @@ -447,16 +513,23 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl ExternalItemProvider provider = AbstractItemManager.this.getExternalItemProvider(plugin); return new ExternalModifier<>(id, Objects.requireNonNull(provider, "Item provider " + plugin + " not found")); }, "external"); + if (VersionHelper.isOrAbove1_20_5()) { + registerDataType((obj) -> { + String name = obj.toString(); + return new CustomNameModifier<>(name); + }, "custom-name"); + registerDataType((obj) -> { + String name = obj.toString(); + return new ItemNameModifier<>(name); + }, "item-name", "display-name"); + } else { + registerDataType((obj) -> { + String name = obj.toString(); + return new CustomNameModifier<>(name); + }, "custom-name", "item-name", "display-name"); + } registerDataType((obj) -> { - String name = obj.toString(); - return new CustomNameModifier<>(Config.nonItalic() ? "" + name : name); - }, "custom-name"); - registerDataType((obj) -> { - String name = obj.toString(); - return new ItemNameModifier<>(Config.nonItalic() ? "" + name : name); - }, "item-name", "display-name"); - registerDataType((obj) -> { - List lore = MiscUtils.getAsStringList(obj).stream().map(it -> "" + it).toList(); + List lore = MiscUtils.getAsStringList(obj); return new LoreModifier<>(lore); }, "lore", "display-lore", "description"); registerDataType((obj) -> { @@ -482,6 +555,38 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return new TagsModifier<>(data); }, "tags", "tag", "nbt"); } + registerDataType((object -> { + MutableInt mutableInt = new MutableInt(0); + List attributeModifiers = ResourceConfigUtils.parseConfigAsList(object, (map) -> { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.item.data.attribute_modifiers.missing_type"); + Key nativeType = AttributeModifiersModifier.getNativeAttributeName(Key.of(type)); + AttributeModifier.Slot slot = AttributeModifier.Slot.valueOf(map.getOrDefault("slot", "any").toString().toUpperCase(Locale.ENGLISH)); + Key id = Optional.ofNullable(map.get("id")).map(String::valueOf).map(Key::of).orElseGet(() -> { + mutableInt.add(1); + return Key.of("craftengine", "modifier_" + mutableInt.intValue()); + }); + double amount = ResourceConfigUtils.getAsDouble( + ResourceConfigUtils.requireNonNullOrThrow(map.get("amount"), "warning.config.item.data.attribute_modifiers.missing_amount"), "amount" + ); + AttributeModifier.Operation operation = AttributeModifier.Operation.valueOf( + ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("operation"), "warning.config.item.data.attribute_modifiers.missing_operation").toUpperCase(Locale.ENGLISH) + ); + AttributeModifier.Display display = null; + if (VersionHelper.isOrAbove1_21_6() && map.containsKey("display")) { + Map displayMap = MiscUtils.castToMap(map.get("display"), false); + AttributeModifier.Display.Type displayType = AttributeModifier.Display.Type.valueOf(ResourceConfigUtils.requireNonEmptyStringOrThrow(displayMap.get("type"), "warning.config.item.data.attribute_modifiers.display.missing_type").toUpperCase(Locale.ENGLISH)); + if (displayType == AttributeModifier.Display.Type.OVERRIDE) { + String miniMessageValue = ResourceConfigUtils.requireNonEmptyStringOrThrow(displayMap.get("value"), "warning.config.item.data.attribute_modifiers.display.missing_value"); + display = new AttributeModifier.Display(displayType, miniMessageValue); + } else { + display = new AttributeModifier.Display(displayType, null); + } + } + return new AttributeModifier(nativeType.value(), slot, id, + amount, operation, display); + }); + return new AttributeModifiersModifier<>(attributeModifiers); + }), "attributes", "attribute-modifiers", "attribute-modifier"); registerDataType((obj) -> { boolean value = TypeUtils.checkType(obj, Boolean.class); return new UnbreakableModifier<>(value); @@ -504,8 +609,12 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl 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); + return new TrimModifier<>(Key.of(material), Key.of(pattern)); }, "trim"); + registerDataType((obj) -> { + List components = MiscUtils.getAsStringList(obj).stream().map(Key::of).toList(); + return new HideTooltipModifier<>(components); + }, "hide-tooltip", "hide-flags"); registerDataType((obj) -> { Map data = MiscUtils.castToMap(obj, false); Map arguments = new HashMap<>(); @@ -668,35 +777,44 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl ) { if (model.property() instanceof LegacyModelPredicate predicate) { String predicateId = predicate.legacyPredicateId(materialId); - for (Map.Entry>, ItemModel> entry : model.whenMap().entrySet()) { - List cases = entry.getKey().fallbackOrMapPrimary(List::of); - for (String caseValue : cases) { - Number legacyValue = predicate.toLegacyValue(caseValue); - if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { - if (legacyValue.floatValue() > 1f) { - continue; + for (Map.Entry>, ItemModel> entry : model.whenMap().entrySet()) { + List cases = entry.getKey().fallbackOrMapPrimary(List::of); + for (JsonElement caseValue : cases) { + if (caseValue instanceof JsonPrimitive primitive) { + Number legacyValue; + if (primitive.isBoolean()) { + legacyValue = predicate.toLegacyValue(primitive.getAsBoolean()); + } else if (primitive.isString()) { + legacyValue = predicate.toLegacyValue(primitive.getAsString()); + } else { + legacyValue = predicate.toLegacyValue(primitive.getAsNumber()); } - } - Map merged = mergePredicates( - parentPredicates, - predicateId, - legacyValue - ); - // Additional check for crossbow - if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { - merged = mergePredicates( + if (predicate instanceof TrimMaterialSelectProperty) { + if (legacyValue.floatValue() > 1f) { + continue; + } + } + Map merged = mergePredicates( + parentPredicates, + predicateId, + legacyValue + ); + // Additional check for crossbow + if (predicate instanceof ChargeTypeSelectProperty && materialId.equals(ItemKeys.CROSSBOW)) { + merged = mergePredicates( + merged, + "charged", + 1 + ); + } + processModelRecursively( + entry.getValue(), merged, - "charged", - 1 + resultList, + materialId, + customModelData ); } - processModelRecursively( - entry.getValue(), - merged, - resultList, - materialId, - customModelData - ); } } // Additional check for crossbow @@ -713,7 +831,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl materialId, customModelData ); - } else if (predicate instanceof TrimMaterialSelectProperty property && property.isArmor(materialId)) { + } else if (predicate instanceof TrimMaterialSelectProperty) { processModelRecursively( model.fallBack(), mergePredicates( 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 d527aac2f..6b4e70569 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 @@ -5,27 +5,74 @@ import net.momirealms.craftengine.core.util.Key; public final class ComponentKeys { private ComponentKeys() {} + public static final Key ATTRIBUTE_MODIFIERS = Key.of("minecraft", "attribute_modifiers"); + public static final Key BANNER_PATTERN = Key.of("minecraft", "banner_patterns"); + public static final Key BASE_COLOR = Key.of("minecraft", "base_color"); + public static final Key BEES = Key.of("minecraft", "bees"); + public static final Key BLOCK_ENTITY_DATA = Key.of("minecraft", "block_entity_data"); + public static final Key BLOCK_STATE = Key.of("minecraft", "block_state"); + public static final Key BLOCKS_ATTACK = Key.of("minecraft", "blocks_attacks"); + public static final Key BREAK_SOUND = Key.of("minecraft", "break_sound"); + public static final Key BUCKET_ENTITY_DATA = Key.of("minecraft", "bucket_entity_data"); + public static final Key BUNDLE_CONTENTS = Key.of("minecraft", "bundle_contents"); + public static final Key CAN_BREAK = Key.of("minecraft", "can_break"); + public static final Key CAN_PLACE_ON = Key.of("minecraft", "can_place_on"); + public static final Key CHARGED_PROJECTILES = Key.of("minecraft", "charged_projectiles"); + public static final Key CONSUMABLE = Key.of("minecraft", "consumable"); + public static final Key CONTAINER = Key.of("minecraft", "container"); + public static final Key CONTAINER_LOOT = Key.of("minecraft", "container_loot"); + public static final Key CUSTOM_DATA = Key.of("minecraft", "custom_data"); public static final Key CUSTOM_MODEL_DATA = Key.of("minecraft", "custom_model_data"); public static final Key CUSTOM_NAME = Key.of("minecraft", "custom_name"); - public static final Key ITEM_NAME = Key.of("minecraft", "item_name"); - public static final Key LORE = Key.of("minecraft", "lore"); public static final Key DAMAGE = Key.of("minecraft", "damage"); - public static final Key MAX_DAMAGE = Key.of("minecraft", "max_damage"); + public static final Key DAMAGE_RESISTANT = Key.of("minecraft", "damage_resistant"); + public static final Key DEBUG_STICK_STATE = Key.of("minecraft", "debug_stick_state"); + public static final Key DEATH_PROTECTION = Key.of("minecraft", "death_protection"); + public static final Key DYED_COLOR = Key.of("minecraft", "dyed_color"); + public static final Key ENCHANTABLE = Key.of("minecraft", "enchantable"); public static final Key ENCHANTMENT_GLINT_OVERRIDE = Key.of("minecraft", "enchantment_glint_override"); public static final Key ENCHANTMENTS = Key.of("minecraft", "enchantments"); - public static final Key STORED_ENCHANTMENTS = Key.of("minecraft", "stored_enchantments"); - public static final Key UNBREAKABLE = Key.of("minecraft", "unbreakable"); - public static final Key MAX_STACK_SIZE = Key.of("minecraft", "max_stack_size"); + public static final Key ENTITY_DATA = Key.of("minecraft", "entity_data"); public static final Key EQUIPPABLE = Key.of("minecraft", "equippable"); - public static final Key ITEM_MODEL = Key.of("minecraft", "item_model"); - public static final Key TOOLTIP_STYLE = Key.of("minecraft", "tooltip_style"); - public static final Key JUKEBOX_PLAYABLE = Key.of("minecraft", "jukebox_playable"); - public static final Key TRIM = Key.of("minecraft", "trim"); - public static final Key REPAIR_COST = Key.of("minecraft", "repair_cost"); - public static final Key CUSTOM_DATA = Key.of("minecraft", "custom_data"); - 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"); public static final Key FIREWORK_EXPLOSION = Key.of("minecraft", "firework_explosion"); + public static final Key FIREWORKS = Key.of("minecraft", "fireworks"); + public static final Key FOOD = Key.of("minecraft", "food"); + public static final Key GLIDER = Key.of("minecraft", "glider"); + public static final Key INSTRUMENT = Key.of("minecraft", "instrument"); + public static final Key INTANGIBLE_PROJECTILE = Key.of("minecraft", "intangible_projectile"); + public static final Key ITEM_MODEL = Key.of("minecraft", "item_model"); + public static final Key ITEM_NAME = Key.of("minecraft", "item_name"); + public static final Key JUKEBOX_PLAYABLE = Key.of("minecraft", "jukebox_playable"); + public static final Key LOCK = Key.of("minecraft", "lock"); + public static final Key LODESTONE_TRACKER = Key.of("minecraft", "lodestone_tracker"); + public static final Key LORE = Key.of("minecraft", "lore"); + public static final Key MAP_COLOR = Key.of("minecraft", "map_color"); + public static final Key MAP_DECORATIONS = Key.of("minecraft", "map_decorations"); + public static final Key MAP_ID = Key.of("minecraft", "map_id"); + public static final Key MAX_DAMAGE = Key.of("minecraft", "max_damage"); + public static final Key MAX_STACK_SIZE = Key.of("minecraft", "max_stack_size"); + public static final Key NOTE_BLOCK_SOUND = Key.of("minecraft", "note_block_sound"); + public static final Key OMINOUS_BOTTLE_AMPLIFIER = Key.of("minecraft", "ominous_bottle_amplifier"); + public static final Key POT_DECORATIONS = Key.of("minecraft", "pot_decorations"); + public static final Key POTION_CONTENTS = Key.of("minecraft", "potion_contents"); + public static final Key POTION_DURATION_SCALE = Key.of("minecraft", "potion_duration_scale"); + public static final Key PROFILE = Key.of("minecraft", "profile"); + public static final Key PROVIDES_BANNER_PATTERN = Key.of("minecraft", "provides_banner_patterns"); + public static final Key PROVIDES_TRIM_MATERIAL = Key.of("minecraft", "provides_trim_material"); + public static final Key RARITY = Key.of("minecraft", "rarity"); + public static final Key RECIPES = Key.of("minecraft", "recipes"); + public static final Key REPAIRABLE = Key.of("minecraft", "repairable"); + public static final Key REPAIR_COST = Key.of("minecraft", "repair_cost"); + public static final Key STORED_ENCHANTMENTS = Key.of("minecraft", "stored_enchantments"); + public static final Key SUSPICIOUS_STEW_EFFECTS = Key.of("minecraft", "suspicious_stew_effects"); + public static final Key TOOL = Key.of("minecraft", "tool"); + public static final Key TOOLTIP_DISPLAY = Key.of("minecraft", "tooltip_display"); + public static final Key TOOLTIP_STYLE = Key.of("minecraft", "tooltip_style"); + public static final Key TRIM = Key.of("minecraft", "trim"); + public static final Key UNBREAKABLE = Key.of("minecraft", "unbreakable"); + public static final Key USE_COOLDOWN = Key.of("minecraft", "use_cooldown"); + public static final Key USE_REMAINDER = Key.of("minecraft", "use_remainder"); + public static final Key WEAPON = Key.of("minecraft", "weapon"); + public static final Key WRITABLE_BOOK_CONTENT = Key.of("minecraft", "writable_book_content"); + public static final Key WRITTEN_BOOK_CONTENT = Key.of("minecraft", "written_book_content"); } 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 f3dd338a7..b1f37784b 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 @@ -6,8 +6,8 @@ import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; 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 net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -17,7 +17,7 @@ public interface CustomItem extends BuildableItem { Key id(); - Holder idHolder(); + UniqueKey uniqueId(); Key material(); @@ -25,14 +25,10 @@ public interface CustomItem extends BuildableItem { ItemDataModifier[] dataModifiers(); - Map> dataModifierMap(); - boolean hasClientBoundDataModifier(); ItemDataModifier[] clientBoundDataModifiers(); - Map> clientBoundDataModifierMap(); - ItemSettings settings(); default boolean is(Key tag) { @@ -51,7 +47,7 @@ public interface CustomItem extends BuildableItem { List behaviors(); interface Builder { - Builder id(Holder id); + Builder id(UniqueKey id); Builder clientBoundMaterial(Key clientBoundMaterialKey); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/DelayedInitItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/DelayedInitItem.java deleted file mode 100644 index 2e6db264f..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/DelayedInitItem.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.momirealms.craftengine.core.item; - -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.Key; - -public class DelayedInitItem { - private final Key itemId; - private Item item; - - public DelayedInitItem(Key itemId) { - this.itemId = itemId; - } - - public Item getItem() { - if (this.item == null) { - this.item = CraftEngine.instance().itemManager().createWrappedItem(this.itemId, null); - if (this.item == null) { - CraftEngine.instance().logger().warn("Could not create item: " + this.itemId); - } - } - return this.item; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ExternalItemProvider.java b/core/src/main/java/net/momirealms/craftengine/core/item/ExternalItemProvider.java index f5cea3ada..14dd780d8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ExternalItemProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ExternalItemProvider.java @@ -8,4 +8,6 @@ public interface ExternalItemProvider { @Nullable I build(String id, ItemBuildContext context); + + String id(I item); } 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 237eb3d0e..86b4c4729 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 @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.item.data.Trim; 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.craftengine.core.util.UniqueKey; import net.momirealms.sparrow.nbt.Tag; import java.util.List; @@ -24,6 +25,8 @@ import java.util.Optional; */ public interface Item { + boolean isEmpty(); + Optional> getCustomItem(); Optional> getItemBehavior(); @@ -36,6 +39,8 @@ public interface Item { Key vanillaId(); + UniqueKey recipeIngredientId(); + Optional customId(); Item customId(Key id); @@ -136,7 +141,9 @@ public interface Item { Object getJavaTag(Object... path); - Tag getNBTTag(Object... path); + Tag getTag(Object... path); + + Object getExactTag(Object... path); Item setTag(Object value, Object... path); @@ -148,13 +155,17 @@ public interface Item { void removeComponent(Object type); + void setExactComponent(Object type, Object value); + Object getExactComponent(Object type); Object getJavaComponent(Object type); JsonElement getJsonComponent(Object type); - Tag getNBTComponent(Object type); + Tag getSparrowNBTComponent(Object type); + + Object getNBTComponent(Object type); void setComponent(Object type, Object value); 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 f0af10fe0..d403ba310 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 @@ -10,6 +10,7 @@ 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; +import net.momirealms.craftengine.core.util.UniqueKey; import net.momirealms.sparrow.nbt.Tag; import java.util.List; @@ -37,7 +38,7 @@ public abstract class ItemFactory, I> { protected abstract Object getJavaTag(W item, Object... path); - protected abstract Tag getNBTTag(W item, Object... path); + protected abstract Tag getTag(W item, Object... path); protected abstract void setTag(W item, Object value, Object... path); @@ -49,11 +50,17 @@ public abstract class ItemFactory, I> { protected abstract Object getExactComponent(W item, Object type); + protected abstract Object getExactTag(W item, Object... path); + + protected abstract void setExactComponent(W item, Object type, Object value); + protected abstract Object getJavaComponent(W item, Object type); protected abstract JsonElement getJsonComponent(W item, Object type); - protected abstract Tag getNBTComponent(W item, Object type); + protected abstract Tag getSparrowNBTComponent(W item, Object type); + + protected abstract Object getNBTComponent(W item, Object type); protected abstract boolean hasComponent(W item, Object type); @@ -200,4 +207,8 @@ public abstract class ItemFactory, I> { protected abstract W transmuteCopy(W item, Key newItem, int amount); protected abstract W unsafeTransmuteCopy(W item, Object newItem, int count); + + protected abstract boolean isEmpty(W item); + + protected abstract UniqueKey recipeIngredientID(W item); } 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 aa1821802..434ae4d65 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,16 +2,19 @@ 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.equipment.Equipment; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; -import net.momirealms.craftengine.core.pack.misc.Equipment; +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel; import net.momirealms.craftengine.core.pack.model.ModernItemModel; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigParser; -import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.UniqueKey; import org.incendo.cloud.suggestion.Suggestion; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -21,28 +24,33 @@ public interface ItemManager extends Manageable, ModelGenerator { void registerDataType(Function> factory, String... alias); - ConfigParser parser(); + Map equipments(); + + ConfigParser[] parsers(); Map> legacyItemOverrides(); Map> modernItemOverrides(); - Map equipmentsToGenerate(); - Map modernItemModels1_21_4(); Map> modernItemModels1_21_2(); Collection vanillaItems(); + @Nullable T buildCustomItemStack(Key id, @Nullable Player player); + @Nullable T buildItemStack(Key id, @Nullable Player player); + @Nullable Item createCustomWrappedItem(Key id, @Nullable Player player); + @Nullable Item createWrappedItem(Key id, @Nullable Player player); + @NotNull Item wrap(T itemStack); Item fromByteArray(byte[] bytes); @@ -57,6 +65,8 @@ public interface ItemManager extends Manageable, ModelGenerator { boolean registerExternalItemProvider(ExternalItemProvider externalItemProvider); + Optional getEquipment(Key key); + Optional> getCustomItem(Key key); Optional> getItemBehavior(Key key); @@ -75,11 +85,11 @@ public interface ItemManager extends Manageable, ModelGenerator { boolean addCustomItem(CustomItem customItem); - List> tagToItems(Key tag); + List tagToItems(Key tag); - List> tagToVanillaItems(Key tag); + List tagToVanillaItems(Key tag); - List> tagToCustomItems(Key tag); + List tagToCustomItems(Key tag); int fuelTime(T itemStack); @@ -90,4 +100,16 @@ public interface ItemManager extends Manageable, ModelGenerator { Collection cachedTotemSuggestions(); boolean isVanillaItem(Key item); + + Item decode(FriendlyByteBuf byteBuf); + + void encode(FriendlyByteBuf byteBuf, Item item); + + Item s2c(Item item, Player player); + + Item c2s(Item item); + + UniqueIdItem uniqueEmptyItem(); + + Item applyTrim(Item base, Item addition, Item template, Key pattern); } \ No newline at end of file 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 936a84e84..9295d1745 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 @@ -4,11 +4,14 @@ import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta; import net.momirealms.craftengine.core.entity.projectile.ProjectileType; +import net.momirealms.craftengine.core.item.equipment.ComponentBasedEquipment; +import net.momirealms.craftengine.core.item.equipment.Equipment; 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.*; -import net.momirealms.craftengine.core.pack.misc.EquipmentLayerType; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.*; @@ -22,8 +25,6 @@ import java.util.stream.Collectors; public class ItemSettings { int fuelTime; Set tags = Set.of(); - @Nullable - ItemEquipment equipment; boolean canRepair = true; List anvilRepairItems = List.of(); boolean renameable = true; @@ -37,13 +38,22 @@ public class ItemSettings { List invulnerable = List.of(); boolean canEnchant = true; float compostProbability= 0.5f; + boolean respectRepairableComponent = false; + @Nullable + ItemEquipment equipment; private ItemSettings() {} public List> modifiers() { ArrayList> modifiers = new ArrayList<>(); - if (VersionHelper.isOrAbove1_21_2() && this.equipment != null) { - modifiers.add(new EquippableModifier<>(this.equipment.data())); + if (this.equipment != null) { + EquipmentData data = this.equipment.equipmentData(); + if (data != null) { + modifiers.add(new EquippableModifier<>(data)); + } + if (!this.equipment.clientBoundModel().asBoolean(Config.globalClientboundModel())) { + modifiers.addAll(this.equipment.equipment().modifiers()); + } } if (VersionHelper.isOrAbove1_20_5() && this.foodData != null) { modifiers.add(new FoodModifier<>(this.foodData.nutrition(), this.foodData.saturation(), false)); @@ -51,6 +61,16 @@ public class ItemSettings { return modifiers; } + public List> clientBoundModifiers() { + ArrayList> modifiers = new ArrayList<>(); + if (this.equipment != null) { + if (this.equipment.clientBoundModel().asBoolean(Config.globalClientboundModel())) { + modifiers.addAll(this.equipment.equipment().modifiers()); + } + } + return modifiers; + } + public static ItemSettings of() { return new ItemSettings(); } @@ -78,6 +98,7 @@ public class ItemSettings { newSettings.invulnerable = settings.invulnerable; newSettings.canEnchant = settings.canEnchant; newSettings.compostProbability = settings.compostProbability; + newSettings.respectRepairableComponent = settings.respectRepairableComponent; return newSettings; } @@ -129,6 +150,10 @@ public class ItemSettings { return anvilRepairItems; } + public boolean respectRepairableComponent() { + return respectRepairableComponent; + } + @Nullable public FoodData foodData() { return foodData; @@ -237,6 +262,11 @@ public class ItemSettings { return this; } + public ItemSettings respectRepairableComponent(boolean respectRepairableComponent) { + this.respectRepairableComponent = respectRepairableComponent; + return this; + } + public ItemSettings invulnerable(List invulnerable) { this.invulnerable = invulnerable; return this; @@ -300,22 +330,41 @@ public class ItemSettings { registerFactory("equippable", (value -> { Map args = MiscUtils.castToMap(value, false); EquipmentData data = EquipmentData.fromMap(args); - ItemEquipment itemEquipment = new ItemEquipment(data); - for (Map.Entry entry : args.entrySet()) { - EquipmentLayerType layerType = EquipmentLayerType.byId(entry.getKey()); - if (layerType != null) { - itemEquipment.addLayer(layerType, ItemEquipment.Layer.fromConfig(entry.getValue())); - } - } + ComponentBasedEquipment componentBasedEquipment = ComponentBasedEquipment.FACTORY.create(data.assetId(), args); + ((AbstractItemManager) CraftEngine.instance().itemManager()).addOrMergeEquipment(componentBasedEquipment); + ItemEquipment itemEquipment = new ItemEquipment(Tristate.FALSE, data, componentBasedEquipment); return settings -> settings.equipment(itemEquipment); })); + registerFactory("equipment", (value -> { + Map args = MiscUtils.castToMap(value, false); + Tristate clientBoundModel = Tristate.of((Boolean) args.get("client-bound-model")); + Key assetId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(args.get("asset-id"), "warning.config.item.settings.equipment.missing_asset_id")); + Optional optionalEquipment = CraftEngine.instance().itemManager().getEquipment(assetId); + if (optionalEquipment.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.item.settings.equipment.invalid_asset_id"); + } + if (VersionHelper.isOrAbove1_21_2() && args.containsKey("slot")) { + if (optionalEquipment.get() instanceof ComponentBasedEquipment) { + EquipmentData data = EquipmentData.fromMap(args); + return settings -> settings.equipment(new ItemEquipment(clientBoundModel, data, optionalEquipment.get())); + } else { + // trim based + Map copiedArgs = new HashMap<>(args); + copiedArgs.put("asset-id", Config.sacrificedVanillaArmorType()); + EquipmentData data = EquipmentData.fromMap(copiedArgs); + return settings -> settings.equipment(new ItemEquipment(clientBoundModel, data, optionalEquipment.get())); + } + } else { + return settings -> settings.equipment(new ItemEquipment(clientBoundModel, null, optionalEquipment.get())); + } + })); registerFactory("can-place", (value -> { boolean bool = ResourceConfigUtils.getAsBoolean(value, "can-place"); return settings -> settings.canPlaceRelatedVanillaBlock(bool); })); registerFactory("projectile", (value -> { Map args = MiscUtils.castToMap(value, false); - Key customTridentItemId = Key.of(Objects.requireNonNull(args.get("item"), "'item should not be null'").toString()); + Key customTridentItemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(args.get("item"), "warning.config.item.settings.projectile.missing_item")); ItemDisplayContext displayType = ItemDisplayContext.valueOf(args.getOrDefault("display-transform", "NONE").toString().toUpperCase(Locale.ENGLISH)); Billboard billboard = Billboard.valueOf(args.getOrDefault("billboard", "FIXED").toString().toUpperCase(Locale.ENGLISH)); Vector3f translation = MiscUtils.getAsVector3f(args.getOrDefault("translation", "0"), "translation"); @@ -337,6 +386,10 @@ public class ItemSettings { boolean bool = ResourceConfigUtils.getAsBoolean(value, "dyeable"); return settings -> settings.dyeable(bool); })); + registerFactory("respect-repairable-component", (value -> { + boolean bool = ResourceConfigUtils.getAsBoolean(value, "respect-repairable-component"); + return settings -> settings.respectRepairableComponent(bool); + })); registerFactory("food", (value -> { Map args = MiscUtils.castToMap(value, false); FoodData data = new FoodData( diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java index 28c122108..6ab3f1d38 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviors.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.item.behavior; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -20,9 +19,8 @@ public class ItemBehaviors { public static final Key EMPTY = Key.withDefaultNamespace("empty", Key.DEFAULT_NAMESPACE); public static void register(Key key, ItemBehaviorFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.ITEM_BEHAVIOR_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.ITEM_BEHAVIOR_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.ITEM_BEHAVIOR_FACTORY) + .register(ResourceKey.create(Registries.ITEM_BEHAVIOR_FACTORY.location(), key), factory); } public static ItemBehavior fromMap(Pack pack, Path path, Key id, Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java b/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java index cb65aff39..41ead315b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/context/UseOnContext.java @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.World; +import org.jetbrains.annotations.NotNull; public class UseOnContext { private final Player player; @@ -24,7 +25,7 @@ public class UseOnContext { this(player.world(), player, hand, stack, hit); } - public UseOnContext(World world, Player player, InteractionHand hand, Item stack, BlockHitResult hit) { + public UseOnContext(@NotNull World world, Player player, InteractionHand hand, @NotNull Item stack, BlockHitResult hit) { this.player = player; this.hand = hand; this.hitResult = hit; @@ -52,6 +53,7 @@ public class UseOnContext { return this.hitResult.isInside(); } + @NotNull public Item getItem() { return this.itemStack; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/data/Trim.java b/core/src/main/java/net/momirealms/craftengine/core/item/data/Trim.java index a1e9d2e6f..e0b95d0eb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/data/Trim.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/data/Trim.java @@ -1,4 +1,6 @@ package net.momirealms.craftengine.core.item.data; -public record Trim(String pattern, String material) { +import net.momirealms.craftengine.core.util.Key; + +public record Trim(Key pattern, Key material) { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/equipment/AbstractEquipment.java b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/AbstractEquipment.java new file mode 100644 index 000000000..19eba975e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/AbstractEquipment.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.item.equipment; + +import net.momirealms.craftengine.core.util.Key; + +public abstract class AbstractEquipment implements Equipment { + protected final Key assetId; + + protected AbstractEquipment(Key assetId) { + this.assetId = assetId; + } + + @Override + public Key assetId() { + return assetId; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/equipment/ComponentBasedEquipment.java b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/ComponentBasedEquipment.java new file mode 100644 index 000000000..d8d52d807 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/ComponentBasedEquipment.java @@ -0,0 +1,147 @@ +package net.momirealms.craftengine.core.item.equipment; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.item.modifier.EquippableAssetIdModifier; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.function.Supplier; + +public class ComponentBasedEquipment extends AbstractEquipment implements Supplier { + public static final Factory FACTORY = new Factory(); + private final EnumMap> layers; + + public ComponentBasedEquipment(Key assetId) { + super(assetId); + this.layers = new EnumMap<>(EquipmentLayerType.class); + } + + @Override + public Key type() { + return Equipments.COMPONENT; + } + + @Override + public List> modifiers() { + return List.of(new EquippableAssetIdModifier<>(this.assetId)); + } + + public EnumMap> layers() { + return layers; + } + + public void addLayer(EquipmentLayerType layerType, List layer) { + this.layers.put(layerType, layer); + } + + @Override + public JsonObject get() { + JsonObject jsonObject = new JsonObject(); + JsonObject layersJson = new JsonObject(); + jsonObject.add("layers", layersJson); + for (Map.Entry> entry : layers.entrySet()) { + EquipmentLayerType type = entry.getKey(); + List layerList = entry.getValue(); + setLayers(layersJson, layerList, type.id()); + } + return jsonObject; + } + + private void setLayers(JsonObject layersJson, List layers, String key) { + if (layers == null || layers.isEmpty()) return; + JsonArray layersArray = new JsonArray(); + for (ComponentBasedEquipment.Layer layer : layers) { + layersArray.add(layer.get()); + } + layersJson.add(key, layersArray); + } + + public static class Factory implements EquipmentFactory { + + @Override + public ComponentBasedEquipment create(Key id, Map args) { + ComponentBasedEquipment equipment = new ComponentBasedEquipment(id); + for (Map.Entry entry : args.entrySet()) { + EquipmentLayerType layerType = EquipmentLayerType.byId(entry.getKey()); + if (layerType != null) { + equipment.addLayer(layerType, Layer.fromConfig(entry.getValue())); + } + } + return equipment; + } + } + + public record Layer(String texture, DyeableData data, boolean usePlayerTexture) implements Supplier { + + @NotNull + public static List fromConfig(Object obj) { + switch (obj) { + case String texture -> { + return List.of(new Layer(texture, null, false)); + } + case Map map -> { + Map data = MiscUtils.castToMap(map, false); + String texture = data.get("texture").toString(); + return List.of(new Layer(texture, + DyeableData.fromObj(data.get("dyeable")), + ResourceConfigUtils.getAsBoolean(data.getOrDefault("use-player-texture", false), "use-player-texture") + )); + } + case List list -> { + List layers = new ArrayList<>(); + for (Object inner : list) { + layers.addAll(fromConfig(inner)); + } + return layers; + } + case null, default -> { + return List.of(); + } + } + } + + @Override + public JsonObject get() { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("texture", texture); + if (this.data != null) { + jsonObject.add("dyeable", this.data.get()); + } + if (this.usePlayerTexture) { + jsonObject.addProperty("use_player_texture", true); + } + return jsonObject; + } + + public record DyeableData(@Nullable Integer colorWhenUndyed) implements Supplier { + + public static DyeableData fromObj(Object obj) { + if (obj instanceof Map map) { + Map data = MiscUtils.castToMap(map, false); + if (data.containsKey("color-when-undyed")) { + return new DyeableData(ResourceConfigUtils.getAsInt(data.get("color-when-undyed"), "color-when-undyed")); + } + } + return new DyeableData(null); + } + + @Override + public JsonObject get() { + JsonObject dyeData = new JsonObject(); + if (this.colorWhenUndyed != null) { + dyeData.addProperty("color_when_undyed", this.colorWhenUndyed); + } + return dyeData; + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/equipment/Equipment.java b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/Equipment.java new file mode 100644 index 000000000..d36d1a885 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/Equipment.java @@ -0,0 +1,15 @@ +package net.momirealms.craftengine.core.item.equipment; + +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.util.Key; + +import java.util.List; + +public interface Equipment { + + Key assetId(); + + Key type(); + + List> modifiers(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/equipment/EquipmentFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/EquipmentFactory.java new file mode 100644 index 000000000..16fe7f862 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/EquipmentFactory.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.item.equipment; + +import net.momirealms.craftengine.core.util.Key; + +import java.util.Map; + +public interface EquipmentFactory { + + Equipment create(Key id, Map args); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/misc/EquipmentLayerType.java b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/EquipmentLayerType.java similarity index 95% rename from core/src/main/java/net/momirealms/craftengine/core/pack/misc/EquipmentLayerType.java rename to core/src/main/java/net/momirealms/craftengine/core/item/equipment/EquipmentLayerType.java index 80ea4cf54..b0a25b94c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/misc/EquipmentLayerType.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/EquipmentLayerType.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.pack.misc; +package net.momirealms.craftengine.core.item.equipment; import java.util.HashMap; import java.util.Map; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/equipment/Equipments.java b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/Equipments.java new file mode 100644 index 000000000..9456b80db --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/Equipments.java @@ -0,0 +1,36 @@ +package net.momirealms.craftengine.core.item.equipment; + +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.ResourceKey; + +import java.util.Map; + +public final class Equipments { + public static final Key TRIM = Key.of("craftengine:trim"); + public static final Key COMPONENT = Key.of("craftengine:component"); + + static { + register(TRIM, TrimBasedEquipment.FACTORY); + register(COMPONENT, ComponentBasedEquipment.FACTORY); + } + + public static void register(Key key, EquipmentFactory factory) { + ((WritableRegistry) BuiltInRegistries.EQUIPMENT_FACTORY) + .register(ResourceKey.create(Registries.EQUIPMENT_FACTORY.location(), key), factory); + } + + public static Equipment fromMap(Key id, Map map) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.equipment.missing_type"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + EquipmentFactory factory = BuiltInRegistries.EQUIPMENT_FACTORY.getValue(key); + if (factory == null) { + throw new LocalizedResourceConfigException("warning.config.equipment.invalid_type", type); + } + return factory.create(id, map); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/equipment/TrimBasedEquipment.java b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/TrimBasedEquipment.java new file mode 100644 index 000000000..6023fd20d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/equipment/TrimBasedEquipment.java @@ -0,0 +1,58 @@ +package net.momirealms.craftengine.core.item.equipment; + +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.modifier.HideTooltipModifier; +import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.item.modifier.TrimModifier; +import net.momirealms.craftengine.core.pack.AbstractPackManager; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class TrimBasedEquipment extends AbstractEquipment { + public static final Factory FACTORY = new Factory(); + private final Key humanoid; + private final Key humanoidLeggings; + + public TrimBasedEquipment(Key assetId, @Nullable Key humanoid, @Nullable Key humanoidLeggings) { + super(assetId); + this.humanoid = humanoid; + this.humanoidLeggings = humanoidLeggings; + } + + @Override + public Key type() { + return Equipments.TRIM; + } + + @Nullable + public Key humanoid() { + return humanoid; + } + + @Nullable + public Key humanoidLeggings() { + return humanoidLeggings; + } + + @Override + public List> modifiers() { + return List.of( + new TrimModifier<>(Key.of(AbstractPackManager.NEW_TRIM_MATERIAL), this.assetId), + new HideTooltipModifier<>(List.of(ComponentKeys.TRIM)) + ); + } + + public static class Factory implements EquipmentFactory { + + @Override + public Equipment create(Key id, Map args) { + Key humanoidId = Optional.ofNullable((String) args.get("humanoid")).map(Key::of).orElse(null); + Key humanoidLeggingsId = Optional.ofNullable((String) args.get("humanoid-leggings")).map(Key::of).orElse(null); + return new TrimBasedEquipment(id, humanoidId, humanoidLeggingsId); + } + } +} 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 a3ec03e7d..63628171d 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 @@ -28,7 +28,7 @@ public class ArgumentModifier implements ItemDataModifier { @Override 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 customData = (CompoundTag) Optional.ofNullable(item.getSparrowNBTComponent(ComponentKeys.CUSTOM_DATA)).orElse(new CompoundTag()); CompoundTag argumentTag = new CompoundTag(); for (Map.Entry entry : this.arguments.entrySet()) { argumentTag.put(entry.getKey(), new StringTag(entry.getValue().get(context))); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/AttributeModifiersModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/AttributeModifiersModifier.java new file mode 100644 index 000000000..1bc71cff2 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/AttributeModifiersModifier.java @@ -0,0 +1,190 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.attribute.AttributeModifier; +import net.momirealms.craftengine.core.attribute.Attributes; +import net.momirealms.craftengine.core.attribute.Attributes1_21; +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.Key; +import net.momirealms.craftengine.core.util.UUIDUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.ListTag; +import net.momirealms.sparrow.nbt.Tag; + +import java.nio.charset.StandardCharsets; +import java.util.*; + +public class AttributeModifiersModifier implements ItemDataModifier { + public static final Map CONVERTOR = new HashMap<>(); + + static { + if (VersionHelper.isOrAbove1_21_2()) { + CONVERTOR.put(Attributes1_21.BURNING_TIME, Attributes.BURNING_TIME); + CONVERTOR.put(Attributes1_21.ARMOR, Attributes.ARMOR); + CONVERTOR.put(Attributes1_21.ARMOR_TOUGHNESS, Attributes.ARMOR_TOUGHNESS); + CONVERTOR.put(Attributes1_21.ATTACK_KNOCKBACK, Attributes.ATTACK_KNOCKBACK); + CONVERTOR.put(Attributes1_21.ATTACK_DAMAGE, Attributes.ATTACK_DAMAGE); + CONVERTOR.put(Attributes1_21.ATTACK_SPEED, Attributes.ATTACK_SPEED); + CONVERTOR.put(Attributes1_21.FLYING_SPEED, Attributes.FLYING_SPEED); + CONVERTOR.put(Attributes1_21.FOLLOW_RANGE, Attributes.FOLLOW_RANGE); + CONVERTOR.put(Attributes1_21.KNOCKBACK_RESISTANCE, Attributes.KNOCKBACK_RESISTANCE); + CONVERTOR.put(Attributes1_21.LUCK, Attributes.LUCK); + CONVERTOR.put(Attributes1_21.MAX_ABSORPTION, Attributes.MAX_ABSORPTION); + CONVERTOR.put(Attributes1_21.MAX_HEALTH, Attributes.MAX_HEALTH); + CONVERTOR.put(Attributes1_21.MOVEMENT_EFFICIENCY, Attributes.MOVEMENT_EFFICIENCY); + CONVERTOR.put(Attributes1_21.SCALE, Attributes.SCALE); + CONVERTOR.put(Attributes1_21.STEP_HEIGHT, Attributes.STEP_HEIGHT); + CONVERTOR.put(Attributes1_21.JUMP_STRENGTH, Attributes.JUMP_STRENGTH); + CONVERTOR.put(Attributes1_21.ENTITY_INTERACTION_RANGE, Attributes.ENTITY_INTERACTION_RANGE); + CONVERTOR.put(Attributes1_21.BLOCK_INTERACTION_RANGE, Attributes.BLOCK_INTERACTION_RANGE); + CONVERTOR.put(Attributes1_21.SPAWN_REINFORCEMENT, Attributes.SPAWN_REINFORCEMENT); + CONVERTOR.put(Attributes1_21.BLOCK_BREAK_SPEED, Attributes.BLOCK_BREAK_SPEED); + CONVERTOR.put(Attributes1_21.GRAVITY, Attributes.GRAVITY); + CONVERTOR.put(Attributes1_21.SAFE_FALL_DISTANCE, Attributes.SAFE_FALL_DISTANCE); + CONVERTOR.put(Attributes1_21.FALL_DAMAGE_MULTIPLIER, Attributes.FALL_DAMAGE_MULTIPLIER); + CONVERTOR.put(Attributes1_21.EXPLOSION_KNOCKBACK_RESISTANCE, Attributes.EXPLOSION_KNOCKBACK_RESISTANCE); + CONVERTOR.put(Attributes1_21.MINING_EFFICIENCY, Attributes.MINING_EFFICIENCY); + CONVERTOR.put(Attributes1_21.OXYGEN_BONUS, Attributes.OXYGEN_BONUS); + CONVERTOR.put(Attributes1_21.SNEAKING_SPEED, Attributes.SNEAKING_SPEED); + CONVERTOR.put(Attributes1_21.SUBMERGED_MINING_SPEED, Attributes.SUBMERGED_MINING_SPEED); + CONVERTOR.put(Attributes1_21.SWEEPING_DAMAGE_RATIO, Attributes.SWEEPING_DAMAGE_RATIO); + CONVERTOR.put(Attributes1_21.WATER_MOVEMENT_EFFICIENCY, Attributes.WATER_MOVEMENT_EFFICIENCY); + } else { + CONVERTOR.put(Attributes.BURNING_TIME, Attributes1_21.BURNING_TIME); + CONVERTOR.put(Attributes.ARMOR, Attributes1_21.ARMOR); + CONVERTOR.put(Attributes.ARMOR_TOUGHNESS, Attributes1_21.ARMOR_TOUGHNESS); + CONVERTOR.put(Attributes.ATTACK_KNOCKBACK, Attributes1_21.ATTACK_KNOCKBACK); + CONVERTOR.put(Attributes.ATTACK_DAMAGE, Attributes1_21.ATTACK_DAMAGE); + CONVERTOR.put(Attributes.ATTACK_SPEED, Attributes1_21.ATTACK_SPEED); + CONVERTOR.put(Attributes.FLYING_SPEED, Attributes1_21.FLYING_SPEED); + CONVERTOR.put(Attributes.FOLLOW_RANGE, Attributes1_21.FOLLOW_RANGE); + CONVERTOR.put(Attributes.KNOCKBACK_RESISTANCE, Attributes1_21.KNOCKBACK_RESISTANCE); + CONVERTOR.put(Attributes.LUCK, Attributes1_21.LUCK); + CONVERTOR.put(Attributes.MAX_ABSORPTION, Attributes1_21.MAX_ABSORPTION); + CONVERTOR.put(Attributes.MAX_HEALTH, Attributes1_21.MAX_HEALTH); + CONVERTOR.put(Attributes.MOVEMENT_EFFICIENCY, Attributes1_21.MOVEMENT_EFFICIENCY); + CONVERTOR.put(Attributes.SCALE, Attributes1_21.SCALE); + CONVERTOR.put(Attributes.STEP_HEIGHT, Attributes1_21.STEP_HEIGHT); + CONVERTOR.put(Attributes.JUMP_STRENGTH, Attributes1_21.JUMP_STRENGTH); + CONVERTOR.put(Attributes.ENTITY_INTERACTION_RANGE, Attributes1_21.ENTITY_INTERACTION_RANGE); + CONVERTOR.put(Attributes.BLOCK_INTERACTION_RANGE, Attributes1_21.BLOCK_INTERACTION_RANGE); + CONVERTOR.put(Attributes.SPAWN_REINFORCEMENT, Attributes1_21.SPAWN_REINFORCEMENT); + CONVERTOR.put(Attributes.BLOCK_BREAK_SPEED, Attributes1_21.BLOCK_BREAK_SPEED); + CONVERTOR.put(Attributes.GRAVITY, Attributes1_21.GRAVITY); + CONVERTOR.put(Attributes.SAFE_FALL_DISTANCE, Attributes1_21.SAFE_FALL_DISTANCE); + CONVERTOR.put(Attributes.FALL_DAMAGE_MULTIPLIER, Attributes1_21.FALL_DAMAGE_MULTIPLIER); + CONVERTOR.put(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE, Attributes1_21.EXPLOSION_KNOCKBACK_RESISTANCE); + CONVERTOR.put(Attributes.MINING_EFFICIENCY, Attributes1_21.MINING_EFFICIENCY); + CONVERTOR.put(Attributes.OXYGEN_BONUS, Attributes1_21.OXYGEN_BONUS); + CONVERTOR.put(Attributes.SNEAKING_SPEED, Attributes1_21.SNEAKING_SPEED); + CONVERTOR.put(Attributes.SUBMERGED_MINING_SPEED, Attributes1_21.SUBMERGED_MINING_SPEED); + CONVERTOR.put(Attributes.SWEEPING_DAMAGE_RATIO, Attributes1_21.SWEEPING_DAMAGE_RATIO); + CONVERTOR.put(Attributes.WATER_MOVEMENT_EFFICIENCY, Attributes1_21.WATER_MOVEMENT_EFFICIENCY); + } + } + + public static Key getNativeAttributeName(final Key attributeName) { + return CONVERTOR.getOrDefault(attributeName, attributeName); + } + + private final List modifiers; + + public AttributeModifiersModifier(List modifiers) { + this.modifiers = modifiers; + } + + public List modifiers() { + return this.modifiers; + } + + @Override + public String name() { + return "attribute-modifiers"; + } + + private static Object previous; + + @Override + public Item apply(Item item, ItemBuildContext context) { + if (VersionHelper.isOrAbove1_21_5()) { + ListTag modifiers = new ListTag(); + for (AttributeModifier modifier : this.modifiers) { + CompoundTag modifierTag = new CompoundTag(); + modifierTag.putString("type", modifier.type()); + modifierTag.putString("slot", modifier.slot().name().toLowerCase(Locale.ENGLISH)); + modifierTag.putString("id", modifier.id().toString()); + modifierTag.putDouble("amount", modifier.amount()); + modifierTag.putString("operation", modifier.operation().id()); + AttributeModifier.Display display = modifier.display(); + if (VersionHelper.isOrAbove1_21_6() && display != null) { + CompoundTag displayTag = new CompoundTag(); + AttributeModifier.Display.Type displayType = display.type(); + displayTag.putString("type", displayType.name().toLowerCase(Locale.ENGLISH)); + if (displayType == AttributeModifier.Display.Type.OVERRIDE) { + displayTag.put("value", AdventureHelper.componentToTag(AdventureHelper.miniMessage().deserialize(display.value(), context.tagResolvers()))); + } + modifierTag.put("display", displayTag); + } + modifiers.add(modifierTag); + } + item.setNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS, modifiers); + } else if (VersionHelper.isOrAbove1_20_5()) { + CompoundTag compoundTag = (CompoundTag) Optional.ofNullable(item.getSparrowNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS)).orElseGet(CompoundTag::new); + ListTag modifiers = new ListTag(); + compoundTag.put("modifiers", modifiers); + for (AttributeModifier modifier : this.modifiers) { + CompoundTag modifierTag = new CompoundTag(); + modifierTag.putString("type", modifier.type()); + modifierTag.putString("slot", modifier.slot().name().toLowerCase(Locale.ENGLISH)); + if (VersionHelper.isOrAbove1_21()) { + modifierTag.putString("id", modifier.id().toString()); + } else { + modifierTag.putIntArray("uuid", UUIDUtils.uuidToIntArray(UUID.nameUUIDFromBytes(modifier.id().toString().getBytes(StandardCharsets.UTF_8)))); + modifierTag.putString("name", modifier.id().toString()); + } + modifierTag.putDouble("amount", modifier.amount()); + modifierTag.putString("operation", modifier.operation().id()); + modifiers.add(modifierTag); + } + item.setNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS, compoundTag); + } else { + ListTag listTag = new ListTag(); + for (AttributeModifier modifier : this.modifiers) { + CompoundTag modifierTag = new CompoundTag(); + modifierTag.putString("AttributeName", modifier.type()); + modifierTag.putString("Name", modifier.id().toString()); + modifierTag.putString("Slot", modifier.slot().name().toLowerCase(Locale.ENGLISH)); + modifierTag.putInt("Operation", modifier.operation().ordinal()); + modifierTag.putDouble("Amount", modifier.amount()); + modifierTag.putIntArray("UUID", UUIDUtils.uuidToIntArray(UUID.nameUUIDFromBytes(modifier.id().toString().getBytes(StandardCharsets.UTF_8)))); + listTag.add(modifierTag); + } + item.setTag(listTag, "AttributeModifiers"); + } + return item; + } + + @Override + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getSparrowNBTComponent(ComponentKeys.ATTRIBUTE_MODIFIERS); + if (previous != null) { + networkData.put(ComponentKeys.ATTRIBUTE_MODIFIERS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.ATTRIBUTE_MODIFIERS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } else { + Tag previous = item.getTag("AttributeModifiers"); + if (previous != null) { + networkData.put("AttributeModifiers", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("AttributeModifiers", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + 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 e9c333e69..3dc223ca3 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 @@ -59,7 +59,7 @@ public class ComponentModifier implements ItemDataModifier { item.setNBTComponent(entry.left(), entry.right()); } if (this.customData != null) { - CompoundTag tag = (CompoundTag) item.getNBTTag(ComponentKeys.CUSTOM_DATA); + CompoundTag tag = (CompoundTag) item.getTag(ComponentKeys.CUSTOM_DATA); if (tag != null) { for (Map.Entry entry : this.customData.entrySet()) { tag.put(entry.getKey(), entry.getValue()); @@ -75,7 +75,7 @@ public class ComponentModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { for (Pair entry : this.arguments) { - Tag previous = item.getNBTComponent(entry.left()); + Tag previous = item.getSparrowNBTComponent(entry.left()); if (previous != null) { networkData.put(entry.left().asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 9634a56c1..f76bb1c78 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 @@ -29,14 +29,14 @@ public class CustomModelDataModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getNBTComponent(ComponentKeys.CUSTOM_MODEL_DATA); + Tag previous = item.getSparrowNBTComponent(ComponentKeys.CUSTOM_MODEL_DATA); if (previous != null) { networkData.put(ComponentKeys.CUSTOM_MODEL_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { networkData.put(ComponentKeys.CUSTOM_MODEL_DATA.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } else { - Tag previous = item.getNBTTag("CustomModelData"); + Tag previous = item.getTag("CustomModelData"); if (previous != null) { networkData.put("CustomModelData", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 ae46ebae5..ecbbbe33a 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,6 +4,7 @@ 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; @@ -13,7 +14,15 @@ public class CustomNameModifier implements ItemDataModifier { private final String argument; public CustomNameModifier(String argument) { - this.argument = argument; + if (Config.addNonItalicTag()) { + if (argument.startsWith("")) { + this.argument = argument; + } else { + this.argument = "" + argument; + } + } else { + this.argument = argument; + } } @Override @@ -30,14 +39,14 @@ public class CustomNameModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getNBTComponent(ComponentKeys.CUSTOM_NAME); + Tag previous = item.getSparrowNBTComponent(ComponentKeys.CUSTOM_NAME); if (previous != null) { networkData.put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { networkData.put(ComponentKeys.CUSTOM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } else { - Tag previous = item.getNBTTag("display", "Name"); + Tag previous = item.getTag("display", "Name"); if (previous != null) { networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 index d85b3133e..a93bbf284 100644 --- 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 @@ -29,14 +29,14 @@ public class DyedColorModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getNBTComponent(ComponentKeys.DYED_COLOR); + Tag previous = item.getSparrowNBTComponent(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"); + Tag previous = item.getTag("display", "color"); if (previous != null) { networkData.put("display.color", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 index 8962c63e0..65392a1b8 100644 --- 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 @@ -47,14 +47,14 @@ public class DynamicLoreModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getNBTComponent(ComponentKeys.LORE); + Tag previous = item.getSparrowNBTComponent(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"); + Tag previous = item.getTag("display", "Lore"); if (previous != null) { networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 baf4e6caf..9168de84a 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 @@ -34,14 +34,14 @@ public class EnchantmentModifier implements ItemDataModifier { 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); + Tag previous = item.getSparrowNBTComponent(ComponentKeys.STORED_ENCHANTMENTS); if (previous != null) { networkData.put(ComponentKeys.STORED_ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { networkData.put(ComponentKeys.STORED_ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } else { - Tag previous = item.getNBTTag("StoredEnchantments"); + Tag previous = item.getTag("StoredEnchantments"); if (previous != null) { networkData.put("StoredEnchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { @@ -50,14 +50,14 @@ public class EnchantmentModifier implements ItemDataModifier { } } else { if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getNBTComponent(ComponentKeys.ENCHANTMENTS); + Tag previous = item.getSparrowNBTComponent(ComponentKeys.ENCHANTMENTS); if (previous != null) { networkData.put(ComponentKeys.ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { networkData.put(ComponentKeys.ENCHANTMENTS.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } else { - Tag previous = item.getNBTTag("Enchantments"); + Tag previous = item.getTag("Enchantments"); if (previous != null) { networkData.put("Enchantments", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableAssetIdModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableAssetIdModifier.java new file mode 100644 index 000000000..48630e358 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EquippableAssetIdModifier.java @@ -0,0 +1,51 @@ +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.item.setting.EquipmentData; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +import java.util.Optional; + +public class EquippableAssetIdModifier implements ItemDataModifier { + private final Key assetId; + + public EquippableAssetIdModifier(Key assetsId) { + this.assetId = assetsId; + } + + @Override + public String name() { + return "equippable-asset-id"; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + Optional optionalData = item.equippable(); + optionalData.ifPresent(data -> item.equippable(new EquipmentData( + data.slot(), + this.assetId, + data.dispensable(), + data.swappable(), + data.damageOnHurt(), + data.equipOnInteract(), + data.cameraOverlay() + ))); + return item; + } + + @Override + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + Tag previous = item.getSparrowNBTComponent(ComponentKeys.EQUIPPABLE); + if (previous != null) { + networkData.put(ComponentKeys.EQUIPPABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.EQUIPPABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + 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 index 38fc4232b..4ab82b684 100644 --- 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 @@ -37,7 +37,7 @@ public class FoodModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - Tag previous = item.getNBTComponent(ComponentKeys.FOOD); + Tag previous = item.getSparrowNBTComponent(ComponentKeys.FOOD); if (previous != null) { networkData.put(ComponentKeys.FOOD.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java new file mode 100644 index 000000000..20c2bab7c --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/HideTooltipModifier.java @@ -0,0 +1,218 @@ +package net.momirealms.craftengine.core.item.modifier; + +import com.google.common.collect.ImmutableMap; +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.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class HideTooltipModifier implements ItemDataModifier { + public static final Map TO_LEGACY; + static { + ImmutableMap.Builder builder = ImmutableMap.builder(); + builder.put(ComponentKeys.ENCHANTMENTS, 1); + builder.put(ComponentKeys.ATTRIBUTE_MODIFIERS, 2); + builder.put(ComponentKeys.UNBREAKABLE, 4); + builder.put(ComponentKeys.CAN_BREAK, 8); + builder.put(ComponentKeys.CAN_PLACE_ON, 16); + builder.put(ComponentKeys.STORED_ENCHANTMENTS, 32); + builder.put(ComponentKeys.POTION_CONTENTS, 32); + builder.put(ComponentKeys.WRITTEN_BOOK_CONTENT, 32); + builder.put(ComponentKeys.FIREWORKS, 32); + builder.put(ComponentKeys.FIREWORK_EXPLOSION, 32); + builder.put(ComponentKeys.BUNDLE_CONTENTS, 32); + builder.put(ComponentKeys.MAP_ID, 32); + builder.put(ComponentKeys.MAP_COLOR, 32); + builder.put(ComponentKeys.MAP_DECORATIONS, 32); + builder.put(ComponentKeys.DYED_COLOR, 64); + builder.put(ComponentKeys.TRIM, 128); + TO_LEGACY = builder.build(); + } + + private final List components; + private final Applier applier; + + public HideTooltipModifier(List components) { + this.components = components; + if (VersionHelper.isOrAbove1_21_5()) { + this.applier = new ModernApplier<>(components); + } else if (VersionHelper.isOrAbove1_20_5()) { + if (components.isEmpty()) { + this.applier = new DummyApplier<>(); + } else if (components.size() == 1) { + this.applier = new SemiModernApplier<>(components.getFirst()); + } else { + List> appliers = new ArrayList<>(); + for (Key key : components) { + appliers.add(new SemiModernApplier<>(key)); + } + this.applier = new CompoundApplier<>(appliers); + } + } else { + this.applier = new LegacyApplier<>(components); + } + } + + public List components() { + return components; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + this.applier.apply(item); + return item; + } + + @Override + public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_21_5()) { + Tag previous = item.getSparrowNBTComponent(ComponentKeys.TOOLTIP_DISPLAY); + if (previous != null) { + networkData.put(ComponentKeys.TOOLTIP_DISPLAY.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.TOOLTIP_DISPLAY.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } else if (VersionHelper.isOrAbove1_20_5()) { + for (Key component : this.components) { + Tag previous = item.getSparrowNBTComponent(component); + if (previous != null) { + networkData.put(component.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(component.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + } else { + Tag previous = item.getTag("HideFlags"); + if (previous != null) { + networkData.put("HideFlags", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("HideFlags", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + return item; + } + + @Override + public String name() { + return "hide-tooltip"; + } + + public interface Applier { + + void apply(Item item); + } + + public static class DummyApplier implements Applier { + + @Override + public void apply(Item item) { + } + } + + public static class SemiModernApplier implements Applier { + private final Key component; + + public SemiModernApplier(Key component) { + this.component = component; + } + + @Override + public void apply(Item item) { + Tag previous = item.getSparrowNBTComponent(this.component); + if (previous instanceof CompoundTag compoundTag) { + compoundTag.putBoolean("show_in_tooltip", false); + item.setNBTComponent(this.component, compoundTag); + } else { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putBoolean("show_in_tooltip", false); + item.setNBTComponent(this.component, compoundTag); + } + } + } + + public record CompoundApplier(List> appliers) implements Applier { + + @Override + public void apply(Item item) { + for (Applier applier : appliers) { + applier.apply(item); + } + } + } + + public static class LegacyApplier implements Applier { + private final int legacyValue; + + public LegacyApplier(List components) { + int i = 0; + for (Key key : components) { + Integer flag = TO_LEGACY.get(key); + if (flag != null) { + i += flag; + } + } + this.legacyValue = i; + } + + public int legacyValue() { + return legacyValue; + } + + @Override + public void apply(Item item) { + Integer previousFlags = (Integer) item.getJavaTag("HideFlags"); + if (previousFlags != null) { + item.setTag(this.legacyValue | previousFlags, "HideFlags"); + } else { + item.setTag(this.legacyValue, "HideFlags"); + } + } + } + + public static class ModernApplier implements Applier { + private final List components; + + public ModernApplier(List components) { + this.components = components.stream().map(Key::toString).collect(Collectors.toList()); + } + + public List components() { + return components; + } + + @Override + public void apply(Item item) { + Map data = MiscUtils.castToMap(item.getJavaComponent(ComponentKeys.TOOLTIP_DISPLAY), true); + if (data == null) { + item.setJavaComponent(ComponentKeys.TOOLTIP_DISPLAY, Map.of("hidden_components", this.components)); + } else { + if (data.get("hidden_components") instanceof List list) { + List hiddenComponents = list.stream().map(Object::toString).toList(); + List mergedComponents = Stream.concat( + hiddenComponents.stream(), + this.components.stream() + ).distinct().toList(); + Map newData = new HashMap<>(data); + newData.put("hidden_components", mergedComponents); + item.setJavaComponent(ComponentKeys.TOOLTIP_DISPLAY, newData); + } else { + Map newData = new HashMap<>(data); + newData.put("hidden_components", this.components); + item.setJavaComponent(ComponentKeys.TOOLTIP_DISPLAY, newData); + } + } + } + } +} 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 0d4cea04d..319cacc13 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 @@ -28,7 +28,7 @@ public class ItemModelModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - Tag previous = item.getNBTComponent(ComponentKeys.ITEM_MODEL); + Tag previous = item.getSparrowNBTComponent(ComponentKeys.ITEM_MODEL); if (previous != null) { networkData.put(ComponentKeys.ITEM_MODEL.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 0171474e1..63cfac93f 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 @@ -30,14 +30,14 @@ public class ItemNameModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getNBTComponent(ComponentKeys.ITEM_NAME); + Tag previous = item.getSparrowNBTComponent(ComponentKeys.ITEM_NAME); if (previous != null) { networkData.put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { networkData.put(ComponentKeys.ITEM_NAME.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } else { - Tag previous = item.getNBTTag("display", "Name"); + Tag previous = item.getTag("display", "Name"); if (previous != null) { networkData.put("display.Name", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 dd5816861..6c5c88a59 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,18 +4,32 @@ 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; import net.momirealms.sparrow.nbt.Tag; +import java.util.ArrayList; import java.util.List; public class LoreModifier implements ItemDataModifier { private final List argument; public LoreModifier(List argument) { - this.argument = argument; + if (Config.addNonItalicTag()) { + List processed = new ArrayList<>(argument.size()); + for (String arg : argument) { + if (arg.startsWith("")) { + processed.add(arg); + } else { + processed.add("" + arg); + } + } + this.argument = processed; + } else { + this.argument = argument; + } } @Override @@ -32,14 +46,14 @@ public class LoreModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getNBTComponent(ComponentKeys.LORE); + Tag previous = item.getSparrowNBTComponent(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"); + Tag previous = item.getTag("display", "Lore"); if (previous != null) { networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 f6461e772..324db069b 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 @@ -36,7 +36,7 @@ public class RemoveComponentModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { for (String component : this.arguments) { - Tag previous = item.getNBTComponent(component); + Tag previous = item.getSparrowNBTComponent(component); if (previous != null) { networkData.put(component, NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } 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 34aaa3ffa..b264c9c33 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 @@ -41,7 +41,7 @@ public class TagsModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { for (Map.Entry entry : this.arguments.entrySet()) { - Tag previous = item.getNBTTag(entry.getKey()); + Tag previous = item.getTag(entry.getKey()); if (previous != null) { networkData.put(entry.getKey(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 af066a977..ac3a38114 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 @@ -28,7 +28,7 @@ public class TooltipStyleModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { - Tag previous = item.getNBTComponent(ComponentKeys.TOOLTIP_STYLE); + Tag previous = item.getSparrowNBTComponent(ComponentKeys.TOOLTIP_STYLE); if (previous != null) { networkData.put(ComponentKeys.TOOLTIP_STYLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 a86adda9b..3a5a32a56 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 @@ -1,16 +1,20 @@ package net.momirealms.craftengine.core.item.modifier; -import net.momirealms.craftengine.core.item.*; +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.item.data.Trim; +import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; public class TrimModifier implements ItemDataModifier { - private final String material; - private final String pattern; + private final Key material; + private final Key pattern; - public TrimModifier(String material, String pattern) { + public TrimModifier(Key material, Key pattern) { this.material = material; this.pattern = pattern; } @@ -22,21 +26,21 @@ public class TrimModifier implements ItemDataModifier { @Override public Item apply(Item item, ItemBuildContext context) { - item.trim(new Trim(this.material, this.pattern)); + item.trim(new Trim(this.pattern, this.material)); return item; } @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getNBTComponent(ComponentKeys.TRIM); + Tag previous = item.getSparrowNBTComponent(ComponentKeys.TRIM); if (previous != null) { networkData.put(ComponentKeys.TRIM.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { networkData.put(ComponentKeys.TRIM.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } else { - Tag previous = item.getNBTTag("Trim"); + Tag previous = item.getTag("Trim"); if (previous != null) { networkData.put("Trim", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { 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 756152329..b1be281a0 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 @@ -29,14 +29,14 @@ public class UnbreakableModifier implements ItemDataModifier { @Override public Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { if (VersionHelper.isOrAbove1_20_5()) { - Tag previous = item.getNBTComponent(ComponentKeys.UNBREAKABLE); + Tag previous = item.getSparrowNBTComponent(ComponentKeys.UNBREAKABLE); if (previous != null) { networkData.put(ComponentKeys.UNBREAKABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { networkData.put(ComponentKeys.UNBREAKABLE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); } } else { - Tag previous = item.getNBTTag("Unbreakable"); + Tag previous = item.getTag("Unbreakable"); if (previous != null) { networkData.put("Unbreakable", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); } else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java index a1e5e3303..69ec59426 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractGroupedRecipe.java @@ -1,10 +1,11 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; -public abstract class AbstractGroupedRecipe implements Recipe { +public abstract class AbstractGroupedRecipe implements FixedResultRecipe { protected final String group; protected final Key id; protected final CustomRecipeResult result; @@ -15,6 +16,11 @@ public abstract class AbstractGroupedRecipe implements Recipe { this.result = result; } + @Override + public T assemble(RecipeInput input, ItemBuildContext context) { + return this.result(context); + } + @Nullable public String group() { return group; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeFactory.java index 4ecd81f55..42f10cfae 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeFactory.java @@ -2,12 +2,7 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.EnumUtils; -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.*; import java.util.*; @@ -21,14 +16,13 @@ public abstract class AbstractRecipeFactory implements RecipeFactory { return MiscUtils.castToMap(getIngredientOrThrow(arguments), true); } - protected Set> ingredientHolders(Map arguments) { - Set> holders = new HashSet<>(); + protected Set ingredientHolders(Map arguments) { + Set holders = new HashSet<>(); for (String item : ingredients(arguments)) { if (item.charAt(0) == '#') { holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); } else { - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.of(item)).orElseThrow( - () -> new LocalizedResourceConfigException("warning.config.recipe.invalid_item", item))); + holders.add(UniqueKey.create(Key.of(item))); } } return holders; 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 280e6b7e3..b39dbb002 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 @@ -5,14 +5,15 @@ import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaRecipeReader; import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20; import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20_5; import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_21_2; +import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_21_5; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; 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.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.UniqueKey; import net.momirealms.craftengine.core.util.VersionHelper; import org.jetbrains.annotations.Nullable; @@ -26,7 +27,6 @@ public abstract class AbstractRecipeManager implements RecipeManager { protected final Map>> byResult = new HashMap<>(); protected final Map>> byIngredient = new HashMap<>(); protected final Set dataPackRecipes = new HashSet<>(); - protected final Set customRecipes = new HashSet<>(); protected final RecipeParser recipeParser; protected boolean isReloading; @@ -41,7 +41,9 @@ public abstract class AbstractRecipeManager implements RecipeManager { } private VanillaRecipeReader initVanillaRecipeReader() { - if (VersionHelper.isOrAbove1_21_2()) { + if (VersionHelper.isOrAbove1_21_5()) { + return new VanillaRecipeReader1_21_5(); + } else if (VersionHelper.isOrAbove1_21_2()) { return new VanillaRecipeReader1_21_2(); } else if (VersionHelper.isOrAbove1_20_5()) { return new VanillaRecipeReader1_20_5(); @@ -57,20 +59,12 @@ public abstract class AbstractRecipeManager implements RecipeManager { this.byId.clear(); this.byResult.clear(); this.byIngredient.clear(); - for (Key key : this.customRecipes) { - unregisterPlatformRecipe(key); - } - this.customRecipes.clear(); } protected void markAsDataPackRecipe(Key key) { this.dataPackRecipes.add(key); } - protected void markAsCustomRecipe(Key key) { - this.customRecipes.add(key); - } - @Override public boolean isDataPackRecipe(Key key) { if (this.isReloading) return false; @@ -137,11 +131,13 @@ public abstract class AbstractRecipeManager implements RecipeManager { protected void registerInternalRecipe(Key id, Recipe recipe) { this.byType.computeIfAbsent(recipe.type(), k -> new ArrayList<>()).add(recipe); this.byId.put(id, recipe); - this.byResult.computeIfAbsent(recipe.result().item().id(), k -> new ArrayList<>()).add(recipe); + if (recipe instanceof FixedResultRecipe fixedResult) { + this.byResult.computeIfAbsent(fixedResult.result().item().id(), k -> new ArrayList<>()).add(recipe); + } HashSet usedKeys = new HashSet<>(); for (Ingredient ingredient : recipe.ingredientsInUse()) { - for (Holder holder : ingredient.items()) { - Key key = holder.value(); + for (UniqueKey holder : ingredient.items()) { + Key key = holder.key(); if (usedKeys.add(key)) { this.byIngredient.computeIfAbsent(key, k -> new ArrayList<>()).add(recipe); } @@ -170,16 +166,17 @@ public abstract class AbstractRecipeManager implements RecipeManager { } Recipe recipe = RecipeTypes.fromMap(id, section); try { - markAsCustomRecipe(id); registerInternalRecipe(id, recipe); registerPlatformRecipe(id, recipe); + } catch (LocalizedResourceConfigException e) { + throw e; } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to register custom recipe " + id, e); } } } - protected abstract void unregisterPlatformRecipe(Key key); + protected abstract void unregisterPlatformRecipe(Key key, boolean isBrewingRecipe); protected abstract void registerPlatformRecipe(Key key, Recipe recipe); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CookingRecipeCategory.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CookingRecipeCategory.java index 98fa1c1cf..d1a09e1cc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CookingRecipeCategory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CookingRecipeCategory.java @@ -3,5 +3,11 @@ package net.momirealms.craftengine.core.item.recipe; public enum CookingRecipeCategory { FOOD, BLOCKS, - MISC + MISC; + + public static final CookingRecipeCategory[] VALUES = CookingRecipeCategory.values(); + + public static CookingRecipeCategory byId(final int id) { + return VALUES[id]; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CraftingRecipeCategory.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CraftingRecipeCategory.java index f656cc754..2f9a6ebc8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CraftingRecipeCategory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CraftingRecipeCategory.java @@ -4,5 +4,11 @@ public enum CraftingRecipeCategory { BUILDING, REDSTONE, EQUIPMENT, - MISC + MISC; + + public static final CraftingRecipeCategory[] VALUES = CraftingRecipeCategory.values(); + + public static CraftingRecipeCategory byId(final int id) { + return VALUES[id]; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java index d7f2e531d..127d5a6b4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java @@ -1,8 +1,8 @@ package net.momirealms.craftengine.core.item.recipe; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -28,7 +28,7 @@ public class CustomBlastingRecipe extends CustomCookingRecipe { String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; int cookingTime = ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"); float experience = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"); - Set> holders = ingredientHolders(arguments); + Set holders = ingredientHolders(arguments); return new CustomBlastingRecipe(id, cookingRecipeCategory(arguments), group, Ingredient.of(holders), cookingTime, experience, parseResult(arguments)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java new file mode 100644 index 000000000..7cb0e8763 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBrewingRecipe.java @@ -0,0 +1,102 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.recipe.input.BrewingInput; +import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class CustomBrewingRecipe implements FixedResultRecipe { + public static final Factory FACTORY = new Factory<>(); + private final Key id; + private final Ingredient container; + private final Ingredient ingredient; + private final CustomRecipeResult result; + + public CustomBrewingRecipe(@NotNull Key id, + @NotNull Ingredient container, + @NotNull Ingredient ingredient, + @NotNull CustomRecipeResult result) { + this.id = id; + this.container = container; + this.ingredient = ingredient; + this.result = result; + } + + @Override + public CustomRecipeResult result() { + return this.result; + } + + @Override + public T result(ItemBuildContext context) { + return this.result.buildItemStack(context); + } + + @SuppressWarnings("unchecked") + @Override + public boolean matches(RecipeInput input) { + BrewingInput brewingInput = (BrewingInput) input; + return this.container.test(brewingInput.container()) && this.ingredient.test(brewingInput.ingredient()); + } + + @Override + public T assemble(RecipeInput input, ItemBuildContext context) { + return this.result(context); + } + + @Override + public List> ingredientsInUse() { + List> ingredients = new ArrayList<>(); + ingredients.add(this.container); + ingredients.add(this.ingredient); + return ingredients; + } + + @Override + public @NotNull Key type() { + return RecipeTypes.BREWING; + } + + @NotNull + public Ingredient container() { + return this.container; + } + + @NotNull + public Ingredient ingredient() { + return this.ingredient; + } + + @Override + public Key id() { + return this.id; + } + + @SuppressWarnings({"DuplicatedCode"}) + public static class Factory implements RecipeFactory { + + @Override + public Recipe create(Key id, Map arguments) { + List container = MiscUtils.getAsStringList(arguments.get("container")); + if (container.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.recipe.brewing.missing_container"); + } + List ingredient = MiscUtils.getAsStringList(arguments.get("ingredient")); + if (ingredient.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.recipe.brewing.missing_ingredient"); + } + return new CustomBrewingRecipe<>(id, + ResourceConfigUtils.requireNonNullOrThrow(toIngredient(container), "warning.config.recipe.brewing.missing_container"), + ResourceConfigUtils.requireNonNullOrThrow(toIngredient(ingredient), "warning.config.recipe.brewing.missing_ingredient"), + parseResult(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java index 007381419..38d7e5aff 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java @@ -1,8 +1,8 @@ package net.momirealms.craftengine.core.item.recipe; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -28,7 +28,7 @@ public class CustomCampfireRecipe extends CustomCookingRecipe { String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; int cookingTime = ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"); float experience = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"); - Set> holders = ingredientHolders(arguments); + Set holders = ingredientHolders(arguments); return new CustomCampfireRecipe(id, cookingRecipeCategory(arguments), group, Ingredient.of(holders), cookingTime, experience, parseResult(arguments)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java index de8f7e4f0..2350a975b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapedRecipe.java @@ -4,10 +4,9 @@ import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -107,7 +106,7 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { } else { optional = this.ingredients.get(j + i * this.width); } - OptimizedIDItem itemStack = input.getItem(j, i); + UniqueIdItem itemStack = input.getItem(j, i); if (!Ingredient.isInstance(optional, itemStack)) { return false; } @@ -156,13 +155,12 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { } char ch = key.charAt(0); List items = MiscUtils.getAsStringList(entry.getValue()); - Set> holders = new HashSet<>(); + Set holders = new HashSet<>(); for (String item : items) { if (item.charAt(0) == '#') { holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); } else { - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.of(item)).orElseThrow( - () -> new LocalizedResourceConfigException("warning.config.recipe.invalid_item", item))); + holders.add(UniqueKey.create(Key.of(item))); } } ingredients.put(ch, Ingredient.of(holders)); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java index 2f71fd2d4..5ff9494e0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomShapelessRecipe.java @@ -3,11 +3,9 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -64,13 +62,12 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { if (ingredientsObject instanceof Map map) { for (Map.Entry entry : (MiscUtils.castToMap(map, false)).entrySet()) { List items = MiscUtils.getAsStringList(entry.getValue()); - Set> holders = new HashSet<>(); + Set holders = new HashSet<>(); for (String item : items) { if (item.charAt(0) == '#') { holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); } else { - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.of(item)).orElseThrow( - () -> new LocalizedResourceConfigException("warning.config.recipe.invalid_item", item))); + holders.add(UniqueKey.create(Key.of(item))); } } ingredients.add(Ingredient.of(holders)); @@ -78,36 +75,33 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { } else if (ingredientsObject instanceof List list) { for (Object obj : list) { if (obj instanceof List inner) { - Set> holders = new HashSet<>(); + Set holders = new HashSet<>(); for (String item : MiscUtils.getAsStringList(inner)) { if (item.charAt(0) == '#') { holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); } else { - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.of(item)).orElseThrow( - () -> new LocalizedResourceConfigException("warning.config.recipe.invalid_item", item))); + holders.add(UniqueKey.create(Key.of(item))); } } ingredients.add(Ingredient.of(holders)); } else { String item = obj.toString(); - Set> holders = new HashSet<>(); + Set holders = new HashSet<>(); if (item.charAt(0) == '#') { holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); } else { - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.of(item)).orElseThrow( - () -> new LocalizedResourceConfigException("warning.config.recipe.invalid_item", item))); + holders.add(UniqueKey.create(Key.of(item))); } ingredients.add(Ingredient.of(holders)); } } } else { String item = ingredientsObject.toString(); - Set> holders = new HashSet<>(); + Set holders = new HashSet<>(); if (item.charAt(0) == '#') { holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); } else { - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.of(item)).orElseThrow( - () -> new LocalizedResourceConfigException("warning.config.recipe.invalid_item", item))); + holders.add(UniqueKey.create(Key.of(item))); } ingredients.add(Ingredient.of(holders)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java index 0a667cdff..8d7c2be96 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java @@ -1,8 +1,8 @@ package net.momirealms.craftengine.core.item.recipe; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -28,7 +28,7 @@ public class CustomSmeltingRecipe extends CustomCookingRecipe { String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; int cookingTime = ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"); float experience = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"); - Set> holders = ingredientHolders(arguments); + Set holders = ingredientHolders(arguments); return new CustomSmeltingRecipe(id, cookingRecipeCategory(arguments), group, Ingredient.of(holders), cookingTime, experience, parseResult(arguments)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index a4c76c2bf..e80872c11 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -7,16 +7,17 @@ import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; -public class CustomSmithingTransformRecipe implements Recipe { +public class CustomSmithingTransformRecipe implements FixedResultRecipe { public static final Factory FACTORY = new Factory<>(); private final Key id; private final CustomRecipeResult result; @@ -52,7 +53,7 @@ public class CustomSmithingTransformRecipe implements Recipe { && checkIngredient(this.addition, smithingInput.addition()); } - private boolean checkIngredient(Ingredient ingredient, OptimizedIDItem item) { + private boolean checkIngredient(Ingredient ingredient, UniqueIdItem item) { if (ingredient != null) { if (item == null || item.isEmpty()) { return false; @@ -86,13 +87,16 @@ public class CustomSmithingTransformRecipe implements Recipe { return this.id; } - @Override + @Nullable public T result(ItemBuildContext context) { return this.result.buildItemStack(context); } @SuppressWarnings("unchecked") - public T assemble(ItemBuildContext context, Item base) { + @Override + public T assemble(RecipeInput input, ItemBuildContext context) { + SmithingInput smithingInput = ((SmithingInput) input); + Item base = smithingInput.base().item(); T result = this.result(context); Item wrappedResult = (Item) CraftEngine.instance().itemManager().wrap(result); Item finalResult = wrappedResult; @@ -105,7 +109,6 @@ public class CustomSmithingTransformRecipe implements Recipe { return finalResult.getItem(); } - @Override public CustomRecipeResult result() { return this.result; } @@ -131,6 +134,9 @@ public class CustomSmithingTransformRecipe implements Recipe { @Override public Recipe create(Key id, Map arguments) { List base = MiscUtils.getAsStringList(arguments.get("base")); + if (base.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.recipe.smithing_transform.missing_base"); + } List addition = MiscUtils.getAsStringList(arguments.get("addition")); List template = MiscUtils.getAsStringList(arguments.get("template-type")); boolean mergeComponents = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("merge-components", true), "merge-components"); @@ -143,19 +149,6 @@ public class CustomSmithingTransformRecipe implements Recipe { ItemDataProcessors.fromMapList(processors) ); } - - private Ingredient toIngredient(List items) { - Set> holders = new HashSet<>(); - for (String item : items) { - if (item.charAt(0) == '#') { - holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); - } else { - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.of(item)).orElseThrow( - () -> new LocalizedResourceConfigException("warning.config.recipe.invalid_item", item))); - } - } - return holders.isEmpty() ? null : Ingredient.of(holders); - } } public static class ItemDataProcessors { @@ -193,9 +186,8 @@ public class CustomSmithingTransformRecipe implements Recipe { } public static void register(Key key, ItemDataProcessor.ProcessorFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.SMITHING_RESULT_PROCESSOR_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.SMITHING_RESULT_PROCESSOR_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.SMITHING_RESULT_PROCESSOR_FACTORY) + .register(ResourceKey.create(Registries.SMITHING_RESULT_PROCESSOR_FACTORY.location(), key), factory); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java new file mode 100644 index 000000000..993fb1a31 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTrimRecipe.java @@ -0,0 +1,137 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; +import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +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 org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class CustomSmithingTrimRecipe implements Recipe { + public static final Factory FACTORY = new Factory<>(); + private final Key id; + private final Ingredient base; + private final Ingredient template; + private final Ingredient addition; + @Nullable // 1.21.5 + private final Key pattern; + + public CustomSmithingTrimRecipe(@NotNull Key id, + @NotNull Ingredient base, + @NotNull Ingredient template, + @NotNull Ingredient addition, + @Nullable Key pattern + ) { + this.id = id; + this.base = base; + this.template = template; + this.addition = addition; + this.pattern = pattern; + if (pattern == null && VersionHelper.isOrAbove1_21_5()) { + throw new IllegalStateException("SmithingTrimRecipe cannot have a null pattern on 1.21.5 and above."); + } + } + + @SuppressWarnings("unchecked") + @Override + public T assemble(RecipeInput input, ItemBuildContext context) { + SmithingInput smithingInput = (SmithingInput) input; + Item processed = (Item) CraftEngine.instance().itemManager().applyTrim((Item) smithingInput.base().item(), (Item) smithingInput.addition().item(), (Item) smithingInput.template().item(), this.pattern); + return processed.getItem(); + } + + @SuppressWarnings("unchecked") + @Override + public boolean matches(RecipeInput input) { + SmithingInput smithingInput = (SmithingInput) input; + return checkIngredient(this.base, smithingInput.base()) + && checkIngredient(this.template, smithingInput.template()) + && checkIngredient(this.addition, smithingInput.addition()); + } + + private boolean checkIngredient(Ingredient ingredient, UniqueIdItem item) { + if (ingredient != null) { + if (item == null || item.isEmpty()) { + return false; + } + return ingredient.test(item); + } else { + return item == null || item.isEmpty(); + } + } + + @Override + public List> ingredientsInUse() { + List> ingredients = new ArrayList<>(); + ingredients.add(this.base); + ingredients.add(this.template); + ingredients.add(this.addition); + return ingredients; + } + + @Override + public @NotNull Key type() { + return RecipeTypes.SMITHING_TRIM; + } + + @Override + public Key id() { + return this.id; + } + + @Nullable + public Ingredient base() { + return this.base; + } + + @Nullable + public Ingredient template() { + return template; + } + + @Nullable + public Ingredient addition() { + return addition; + } + + @Nullable + public Key pattern() { + return pattern; + } + + @SuppressWarnings({"DuplicatedCode"}) + public static class Factory implements RecipeFactory { + + @Override + public Recipe create(Key id, Map arguments) { + List base = MiscUtils.getAsStringList(arguments.get("base")); + if (base.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.recipe.smithing_trim.missing_base"); + } + List addition = MiscUtils.getAsStringList(arguments.get("addition")); + if (addition.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.recipe.smithing_trim.missing_addition"); + } + List template = MiscUtils.getAsStringList(arguments.get("template-type")); + if (template.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.recipe.smithing_trim.missing_template_type"); + } + Key pattern = VersionHelper.isOrAbove1_21_5() ? Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("pattern"), "warning.config.recipe.smithing_trim.missing_pattern")) : null; + return new CustomSmithingTrimRecipe<>(id, + ResourceConfigUtils.requireNonNullOrThrow(toIngredient(base), "warning.config.recipe.smithing_trim.missing_base"), + ResourceConfigUtils.requireNonNullOrThrow(toIngredient(template), "warning.config.recipe.smithing_trim.missing_template_type"), + ResourceConfigUtils.requireNonNullOrThrow(toIngredient(addition), "warning.config.recipe.smithing_trim.missing_addition"), + pattern); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java index 9054a2b02..83939ac29 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java @@ -1,8 +1,8 @@ package net.momirealms.craftengine.core.item.recipe; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -28,7 +28,7 @@ public class CustomSmokingRecipe extends CustomCookingRecipe { String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; int cookingTime = ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"); float experience = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience"); - Set> holders = ingredientHolders(arguments); + Set holders = ingredientHolders(arguments); return new CustomSmokingRecipe(id, cookingRecipeCategory(arguments), group, Ingredient.of(holders), cookingTime, experience, parseResult(arguments)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java index 1d9b4b528..95e91ef77 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java @@ -2,8 +2,8 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.UniqueKey; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -45,7 +45,7 @@ public class CustomStoneCuttingRecipe extends AbstractGroupedRecipe { @Override public Recipe create(Key id, Map arguments) { String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; - Set> holders = ingredientHolders(arguments); + Set holders = ingredientHolders(arguments); return new CustomStoneCuttingRecipe<>(id, group, Ingredient.of(holders), parseResult(arguments)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java new file mode 100644 index 000000000..cbc2df693 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/FixedResultRecipe.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.item.ItemBuildContext; + +public interface FixedResultRecipe extends Recipe { + + T result(ItemBuildContext context); + + CustomRecipeResult result(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java index dac02bfb9..db368e605 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java @@ -1,49 +1,48 @@ package net.momirealms.craftengine.core.item.recipe; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.UniqueKey; import java.util.*; import java.util.function.Predicate; -public class Ingredient implements Predicate>, StackedContents.IngredientInfo> { - private final List> items; +public class Ingredient implements Predicate>, StackedContents.IngredientInfo { + private final List items; - public Ingredient(List> items) { + public Ingredient(List items) { this.items = items; } - public static boolean isInstance(Optional> optionalIngredient, OptimizedIDItem stack) { + public static boolean isInstance(Optional> optionalIngredient, UniqueIdItem stack) { return optionalIngredient.map((ingredient) -> ingredient.test(stack)) .orElseGet(stack::isEmpty); } - public static Ingredient of(List> items) { + public static Ingredient of(List items) { return new Ingredient<>(items); } - public static Ingredient of(Set> items) { + public static Ingredient of(Set items) { return new Ingredient<>(new ArrayList<>(items)); } @Override - public boolean test(OptimizedIDItem optimizedIDItem) { - for (Holder item : this.items()) { - if (optimizedIDItem.is(item)) { + public boolean test(UniqueIdItem uniqueIdItem) { + for (UniqueKey item : this.items()) { + if (uniqueIdItem.is(item)) { return true; } } return false; } - public List> items() { + public List items() { return this.items; } @Override public String toString() { StringJoiner joiner = new StringJoiner(", "); - for (Holder item : this.items()) { + for (UniqueKey item : this.items()) { joiner.add(item.toString()); } return "Ingredient: [" + joiner + "]"; @@ -54,7 +53,7 @@ public class Ingredient implements Predicate>, StackedCont } @Override - public boolean acceptsItem(Holder entry) { + public boolean acceptsItem(UniqueKey entry) { return this.items.contains(entry); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/InvalidRecipeIngredientException.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/InvalidRecipeIngredientException.java new file mode 100644 index 000000000..36ed4d887 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/InvalidRecipeIngredientException.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.item.recipe; + +public class InvalidRecipeIngredientException extends RuntimeException { + private final String ingredient; + + public InvalidRecipeIngredientException(String ingredient) { + this.ingredient = ingredient; + } + + public String ingredient() { + return ingredient; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/OptimizedIDItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/OptimizedIDItem.java deleted file mode 100644 index fc899ff76..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/OptimizedIDItem.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe; - -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.Key; - -public class OptimizedIDItem { - private final T rawItem; - private final Holder idHolder; - - public OptimizedIDItem(Holder idHolder, T rawItem) { - this.idHolder = idHolder; - this.rawItem = rawItem; - } - - public Holder id() { - return idHolder; - } - - public T rawItem() { - return rawItem; - } - - public boolean is(Holder id) { - return idHolder == id; - } - - public boolean isEmpty() { - return idHolder == null; - } - - @Override - public String toString() { - return "OptimizedIDItem{" + - "idHolder=" + idHolder + - '}'; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java index befd2940a..a07812c06 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Recipe.java @@ -11,9 +11,7 @@ public interface Recipe { boolean matches(RecipeInput input); - T result(ItemBuildContext context); - - CustomRecipeResult result(); + T assemble(RecipeInput input, ItemBuildContext context); List> ingredientsInUse(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFactory.java index 63c75b959..6620b3b5c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFactory.java @@ -5,8 +5,12 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigExce 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.UniqueKey; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; public interface RecipeFactory { @@ -22,8 +26,20 @@ public interface RecipeFactory { int count = ResourceConfigUtils.getAsInt(resultMap.getOrDefault("count", 1), "count"); return new CustomRecipeResult( CraftEngine.instance().itemManager().getBuildableItem(Key.of(id)).orElseThrow( - () -> new LocalizedResourceConfigException("warning.config.recipe.invalid_item", id)), + () -> new LocalizedResourceConfigException("warning.config.recipe.invalid_result", id)), count ); } + + default Ingredient toIngredient(List items) { + Set holders = new HashSet<>(); + for (String item : items) { + if (item.charAt(0) == '#') { + holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); + } else { + holders.add(UniqueKey.create(Key.of(item))); + } + } + return holders.isEmpty() ? null : Ingredient.of(holders); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFinder.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFinder.java index 4266cf808..d96375d34 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFinder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeFinder.java @@ -1,14 +1,13 @@ package net.momirealms.craftengine.core.item.recipe; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.UniqueKey; import java.util.List; public class RecipeFinder { - private final StackedContents> stackedContents = new StackedContents<>(); + private final StackedContents stackedContents = new StackedContents<>(); - public void addInput(OptimizedIDItem item) { + public void addInput(UniqueIdItem item) { if (!item.isEmpty()) { this.stackedContents.add(item.id(), 1); } @@ -19,7 +18,7 @@ public class RecipeFinder { return !placementInfo.isImpossibleToPlace() && canCraft(placementInfo.ingredients()); } - private boolean canCraft(List>> rawIngredients) { + private boolean canCraft(List> rawIngredients) { return this.stackedContents.tryPick(rawIngredients); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java index 8d716b772..603c76840 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -21,6 +20,7 @@ public class RecipeTypes { public static final Key STONECUTTING = Key.of("minecraft:stonecutting"); public static final Key SMITHING_TRANSFORM = Key.of("minecraft:smithing_transform"); public static final Key SMITHING_TRIM = Key.of("minecraft:smithing_trim"); + public static final Key BREWING = Key.of("minecraft:brewing"); static { register(SHAPED, CustomShapedRecipe.FACTORY); @@ -31,12 +31,13 @@ public class RecipeTypes { register(CAMPFIRE_COOKING, CustomCampfireRecipe.FACTORY); register(STONECUTTING, CustomStoneCuttingRecipe.FACTORY); register(SMITHING_TRANSFORM, CustomSmithingTransformRecipe.FACTORY); + register(SMITHING_TRIM, CustomSmithingTrimRecipe.FACTORY); + register(BREWING, CustomBrewingRecipe.FACTORY); } public static void register(Key key, RecipeFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.RECIPE_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.RECIPE_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry>) BuiltInRegistries.RECIPE_FACTORY) + .register(ResourceKey.create(Registries.RECIPE_FACTORY.location(), key), factory); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/UniqueIdItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/UniqueIdItem.java new file mode 100644 index 000000000..3166c9d00 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/UniqueIdItem.java @@ -0,0 +1,38 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.util.UniqueKey; +import org.jetbrains.annotations.NotNull; + +public class UniqueIdItem { + private final Item rawItem; + private final UniqueKey uniqueId; + + public UniqueIdItem(@NotNull UniqueKey uniqueId, @NotNull Item rawItem) { + this.uniqueId = uniqueId; + this.rawItem = rawItem; + } + + @NotNull + public UniqueKey id() { + return uniqueId; + } + + @NotNull + public Item item() { + return this.rawItem; + } + + public boolean is(UniqueKey id) { + return this.uniqueId == id; + } + + public boolean isEmpty() { + return this.uniqueId == UniqueKey.AIR; + } + + @Override + public String toString() { + return "UniqueIdItem[" + "uniqueId=" + uniqueId + ", item=" + rawItem.getItem() + ']'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/BrewingInput.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/BrewingInput.java new file mode 100644 index 000000000..c04443a34 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/BrewingInput.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.item.recipe.input; + +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; + +public final class BrewingInput implements RecipeInput { + private final UniqueIdItem container; + private final UniqueIdItem ingredient; + + public BrewingInput(UniqueIdItem container, UniqueIdItem ingredient) { + this.container = container; + this.ingredient = ingredient; + } + + public UniqueIdItem container() { + return container; + } + + public UniqueIdItem ingredient() { + return ingredient; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CraftingInput.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CraftingInput.java index 80a702da1..e07cac354 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CraftingInput.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CraftingInput.java @@ -1,25 +1,25 @@ package net.momirealms.craftengine.core.item.recipe.input; -import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; import net.momirealms.craftengine.core.item.recipe.RecipeFinder; +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class CraftingInput implements RecipeInput { +public final class CraftingInput implements RecipeInput { private final int width; private final int height; - private final List> items; + private final List> items; private final int ingredientCount; private final RecipeFinder finder = new RecipeFinder(); - private CraftingInput(int width, int height, List> items) { + private CraftingInput(int width, int height, List> items) { this.height = height; this.width = width; this.items = items; int i = 0; - for (OptimizedIDItem item : items) { + for (UniqueIdItem item : items) { if (!item.isEmpty()) { i++; this.finder.addInput(item); @@ -32,7 +32,7 @@ public class CraftingInput implements RecipeInput { return finder; } - public static CraftingInput of(int width, int height, List> stacks) { + public static CraftingInput of(int width, int height, List> stacks) { if (width <= 0 || height <= 0) { return new CraftingInput<>(0, 0, Collections.emptyList()); } @@ -43,7 +43,7 @@ public class CraftingInput implements RecipeInput { int maxRow = -1; for (int index = 0; index < width * height; index++) { - OptimizedIDItem item = stacks.get(index); + UniqueIdItem item = stacks.get(index); if (!item.isEmpty()) { int row = index / width; int col = index % width; @@ -65,7 +65,7 @@ public class CraftingInput implements RecipeInput { return new CraftingInput<>(width, height, stacks); } - List> trimmed = new ArrayList<>(newWidth * newHeight); + List> trimmed = new ArrayList<>(newWidth * newHeight); for (int row = minRow; row <= maxRow; row++) { for (int col = minCol; col <= maxCol; col++) { int originalIndex = col + row * width; @@ -92,11 +92,11 @@ public class CraftingInput implements RecipeInput { return items.size(); } - public OptimizedIDItem getItem(int x, int y) { + public UniqueIdItem getItem(int x, int y) { return this.items.get(x + y * width); } - public OptimizedIDItem getItem(int index) { + public UniqueIdItem getItem(int index) { return this.items.get(index); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SingleItemInput.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SingleItemInput.java index c706c38d0..194e992c1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SingleItemInput.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SingleItemInput.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.item.recipe.input; -import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; -public record SingleItemInput(OptimizedIDItem input) implements RecipeInput { +public record SingleItemInput(UniqueIdItem input) implements RecipeInput { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SmithingInput.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SmithingInput.java index 29764fcb5..ec1757f31 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SmithingInput.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SmithingInput.java @@ -1,33 +1,34 @@ package net.momirealms.craftengine.core.item.recipe.input; -import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; +import net.momirealms.craftengine.core.item.recipe.UniqueIdItem; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class SmithingInput implements RecipeInput { - private final OptimizedIDItem base; - private final OptimizedIDItem template; - private final OptimizedIDItem addition; +public final class SmithingInput implements RecipeInput { + private final UniqueIdItem base; + private final UniqueIdItem template; + private final UniqueIdItem addition; - public SmithingInput(@Nullable OptimizedIDItem base, - @Nullable OptimizedIDItem template, - @Nullable OptimizedIDItem addition) { + public SmithingInput(@NotNull UniqueIdItem base, + @Nullable UniqueIdItem template, + @Nullable UniqueIdItem addition) { this.base = base; this.template = template; this.addition = addition; } - @Nullable - public OptimizedIDItem base() { + @NotNull + public UniqueIdItem base() { return base; } @Nullable - public OptimizedIDItem template() { + public UniqueIdItem template() { return template; } @Nullable - public OptimizedIDItem addition() { + public UniqueIdItem addition() { return addition; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyCookingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyCookingRecipe.java new file mode 100644 index 000000000..ad7f11891 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyCookingRecipe.java @@ -0,0 +1,58 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.recipe.CookingRecipeCategory; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Obsolete +public class LegacyCookingRecipe implements LegacyRecipe { + private Item result; + private final CookingRecipeCategory category; + private final String group; + private final LegacyIngredient ingredient; + private final float experience; + private final int cookingTime; + + public LegacyCookingRecipe(LegacyIngredient ingredient, + CookingRecipeCategory category, + float experience, + int cookingTime, + Item result, + String group) { + this.ingredient = ingredient; + this.category = category; + this.experience = experience; + this.cookingTime = cookingTime; + this.result = result; + this.group = group; + } + + @Override + public void applyClientboundData(Player player) { + this.result = CraftEngine.instance().itemManager().s2c(this.result, player); + this.ingredient.applyClientboundData(player); + } + + public static LegacyCookingRecipe read(FriendlyByteBuf buf) { + String group = buf.readUtf(); + CookingRecipeCategory category = CookingRecipeCategory.byId(buf.readVarInt()); + LegacyIngredient ingredient = LegacyIngredient.read(buf); + Item result = CraftEngine.instance().itemManager().decode(buf); + float experience = buf.readFloat(); + int cookingTime = buf.readVarInt(); + return new LegacyCookingRecipe(ingredient, category, experience, cookingTime, result, group); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeUtf(this.group); + buf.writeVarInt(this.category.ordinal()); + this.ingredient.write(buf); + CraftEngine.instance().itemManager().encode(buf, this.result); + buf.writeFloat(this.experience); + buf.writeVarInt(this.cookingTime); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyCustomRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyCustomRecipe.java new file mode 100644 index 000000000..cba9a2038 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyCustomRecipe.java @@ -0,0 +1,24 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Obsolete +public class LegacyCustomRecipe implements LegacyRecipe { + private final CraftingRecipeCategory category; + + public LegacyCustomRecipe(CraftingRecipeCategory category) { + this.category = category; + } + + public static LegacyCustomRecipe read(FriendlyByteBuf buf) { + CraftingRecipeCategory category = CraftingRecipeCategory.byId(buf.readVarInt()); + return new LegacyCustomRecipe(category); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(this.category.ordinal()); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyIngredient.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyIngredient.java new file mode 100644 index 000000000..2d4871aa1 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyIngredient.java @@ -0,0 +1,39 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemManager; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Obsolete +public class LegacyIngredient { + private final Item[] items; + + public LegacyIngredient(Item[] items) { + this.items = items; + } + + public Item[] items() { + return items; + } + + public void write(FriendlyByteBuf buf) { + buf.writeArray(this.items, (byteBuf, item) -> CraftEngine.instance().itemManager().encode(byteBuf, item)); + } + + @SuppressWarnings("unchecked") + public static LegacyIngredient read(FriendlyByteBuf buf) { + Item[] items = buf.readArray(byteBuf -> CraftEngine.instance().itemManager().decode(byteBuf), Item.class); + return new LegacyIngredient(items); + } + + public void applyClientboundData(Player player) { + ItemManager manager = CraftEngine.instance().itemManager(); + for (int i = 0; i < this.items.length; i++) { + Item item = this.items[i]; + this.items[i] = manager.s2c(item, player); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyRecipe.java new file mode 100644 index 000000000..4e41151da --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyRecipe.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.ApiStatus; + +import java.util.function.Function; + +@ApiStatus.Obsolete +public interface LegacyRecipe { + + default void applyClientboundData(Player player) {} + + void write(FriendlyByteBuf buf); + + record Type(Function reader) { + + public LegacyRecipe read(FriendlyByteBuf buf) { + return this.reader.apply(buf); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyRecipeHolder.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyRecipeHolder.java new file mode 100644 index 000000000..ca9d7e17e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyRecipeHolder.java @@ -0,0 +1,53 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; + +public interface LegacyRecipeHolder { + + void write(FriendlyByteBuf buf); + + LegacyRecipe recipe(); + + static LegacyRecipeHolder read(FriendlyByteBuf buf) { + if (VersionHelper.isOrAbove1_20_5()) { + return ModernRecipeHolderImpl.read(buf); + } else { + return LegacyRecipeHolderImpl.read(buf); + } + } + + record LegacyRecipeHolderImpl(Key id, Key type, LegacyRecipe recipe) implements LegacyRecipeHolder { + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeKey(this.type); + buf.writeKey(this.id); + this.recipe.write(buf); + } + + public static LegacyRecipeHolder read(FriendlyByteBuf buf) { + Key type = buf.readKey(); + Key id = buf.readKey(); + return new LegacyRecipeHolderImpl(id, type, BuiltInRegistries.LEGACY_RECIPE_TYPE.getValue(type).read(buf)); + } + } + + record ModernRecipeHolderImpl(Key id, int type, LegacyRecipe recipe) implements LegacyRecipeHolder { + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeKey(this.id); + buf.writeVarInt(this.type); + this.recipe.write(buf); + } + + public static LegacyRecipeHolder read(FriendlyByteBuf buf) { + Key id = buf.readKey(); + int type = buf.readVarInt(); + return new ModernRecipeHolderImpl(id, type, BuiltInRegistries.LEGACY_RECIPE_TYPE.getValue(type).read(buf)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyRecipeTypes.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyRecipeTypes.java new file mode 100644 index 000000000..f162b1be0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyRecipeTypes.java @@ -0,0 +1,68 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceKey; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Obsolete +public final class LegacyRecipeTypes { + private LegacyRecipeTypes() {} + + public static final Key SHAPED_RECIPE = Key.of("crafting_shaped"); + public static final Key SHAPELESS_RECIPE = Key.of("crafting_shapeless"); + public static final Key ARMOR_DYE = Key.of("crafting_special_armordye"); + public static final Key BOOK_CLONING = Key.of("crafting_special_bookcloning"); + public static final Key MAP_CLONING = Key.of("crafting_special_mapcloning"); + public static final Key MAP_EXTENDING = Key.of("crafting_special_mapextending"); + public static final Key FIREWORK_ROCKET = Key.of("crafting_special_firework_rocket"); + public static final Key FIREWORK_STAR = Key.of("crafting_special_firework_star"); + public static final Key FIREWORK_STAR_FADE = Key.of("crafting_special_firework_star_fade"); + public static final Key TIPPED_ARROW = Key.of("crafting_special_tippedarrow"); + public static final Key BANNER_DUPLICATE = Key.of("crafting_special_bannerduplicate"); + public static final Key SHIELD_DECORATION = Key.of("crafting_special_shielddecoration"); + public static final Key SHULKER_BOX_COLORING = Key.of("crafting_special_shulkerboxcoloring"); + public static final Key SUSPICIOUS_STEW = Key.of("crafting_special_suspiciousstew"); + public static final Key REPAIR_ITEM = Key.of("crafting_special_repairitem"); + public static final Key SMELTING_RECIPE = Key.of("smelting"); + public static final Key BLASTING_RECIPE = Key.of("blasting"); + public static final Key SMOKING_RECIPE = Key.of("smoking"); + public static final Key CAMPFIRE_COOKING_RECIPE = Key.of("campfire_cooking"); + public static final Key STONECUTTER = Key.of("stonecutting"); + public static final Key SMITHING_TRANSFORM = Key.of("smithing_transform"); + public static final Key SMITHING_TRIM = Key.of("smithing_trim"); + public static final Key DECORATED_POT_RECIPE = Key.of("crafting_decorated_pot"); + + public static void register() { + register(SHAPED_RECIPE, new LegacyRecipe.Type(LegacyShapedRecipe::read)); + register(SHAPELESS_RECIPE, new LegacyRecipe.Type(LegacyShapelessRecipe::read)); + register(ARMOR_DYE, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(BOOK_CLONING, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(MAP_CLONING, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(MAP_EXTENDING, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(FIREWORK_ROCKET, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(FIREWORK_STAR, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(FIREWORK_STAR_FADE, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(TIPPED_ARROW, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(BANNER_DUPLICATE, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(SHIELD_DECORATION, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(SHULKER_BOX_COLORING, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(SUSPICIOUS_STEW, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(REPAIR_ITEM, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + register(SMELTING_RECIPE, new LegacyRecipe.Type(LegacyCookingRecipe::read)); + register(BLASTING_RECIPE, new LegacyRecipe.Type(LegacyCookingRecipe::read)); + register(SMOKING_RECIPE, new LegacyRecipe.Type(LegacyCookingRecipe::read)); + register(CAMPFIRE_COOKING_RECIPE, new LegacyRecipe.Type(LegacyCookingRecipe::read)); + register(STONECUTTER, new LegacyRecipe.Type(LegacyStoneCuttingRecipe::read)); + register(SMITHING_TRANSFORM, new LegacyRecipe.Type(LegacySmithingTransformRecipe::read)); + register(SMITHING_TRIM, new LegacyRecipe.Type(LegacySmithingTrimRecipe::read)); + register(DECORATED_POT_RECIPE, new LegacyRecipe.Type(LegacyCustomRecipe::read)); + } + + public static void register(Key key, LegacyRecipe.Type type) { + ((WritableRegistry) BuiltInRegistries.LEGACY_RECIPE_TYPE) + .register(ResourceKey.create(Registries.LEGACY_RECIPE_TYPE.location(), key), type); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyShapedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyShapedRecipe.java new file mode 100644 index 000000000..b83159779 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyShapedRecipe.java @@ -0,0 +1,111 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.Function; + +@ApiStatus.Obsolete +public class LegacyShapedRecipe implements LegacyRecipe { + private final int width; + private final int height; + private final List ingredients; + private Item result; + private final String group; + private final CraftingRecipeCategory category; + private final boolean showNotification; + + public LegacyShapedRecipe(int width, int height, + List ingredients, + Item result, + String group, + CraftingRecipeCategory category, + boolean showNotification) { + this.category = category; + this.width = width; + this.height = height; + this.ingredients = ingredients; + this.result = result; + this.group = group; + this.showNotification = showNotification; + } + + private static final Function READER = VersionHelper.isOrAbove1_20_3() ? + (buf) -> { + String group = buf.readUtf(); + int category = buf.readVarInt(); + int width = buf.readVarInt(); + int height = buf.readVarInt(); + int size = width * height; + List ingredients = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + ingredients.add(LegacyIngredient.read(buf)); + } + Item result = CraftEngine.instance().itemManager().decode(buf); + boolean flag = buf.readBoolean(); + return new LegacyShapedRecipe(width, height, ingredients, result, group, CraftingRecipeCategory.byId(category), flag); + } : + (buf) -> { + int width = buf.readVarInt(); + int height = buf.readVarInt(); + String group = buf.readUtf(); + int category = buf.readVarInt(); + int size = width * height; + List ingredients = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + ingredients.add(LegacyIngredient.read(buf)); + } + Item result = CraftEngine.instance().itemManager().decode(buf); + boolean flag = buf.readBoolean(); + return new LegacyShapedRecipe(width, height, ingredients, result, group, CraftingRecipeCategory.byId(category), flag); + }; + + private static final BiConsumer WRITER = VersionHelper.isOrAbove1_20_3() ? + (recipe, buf) -> { + buf.writeUtf(recipe.group); + buf.writeVarInt(recipe.category.ordinal()); + buf.writeVarInt(recipe.width); + buf.writeVarInt(recipe.height); + for (LegacyIngredient ingredient : recipe.ingredients) { + ingredient.write(buf); + } + CraftEngine.instance().itemManager().encode(buf, recipe.result); + buf.writeBoolean(recipe.showNotification); + } : + (recipe, buf) -> { + buf.writeVarInt(recipe.width); + buf.writeVarInt(recipe.height); + buf.writeUtf(recipe.group); + buf.writeVarInt(recipe.category.ordinal()); + for (LegacyIngredient ingredient : recipe.ingredients) { + ingredient.write(buf); + } + CraftEngine.instance().itemManager().encode(buf, recipe.result); + buf.writeBoolean(recipe.showNotification); + }; + + @Override + public void applyClientboundData(Player player) { + this.result = CraftEngine.instance().itemManager().s2c(this.result, player); + for (LegacyIngredient ingredient : this.ingredients) { + ingredient.applyClientboundData(player); + } + } + + public static LegacyShapedRecipe read(FriendlyByteBuf buf) { + return READER.apply(buf); + } + + @Override + public void write(FriendlyByteBuf buf) { + WRITER.accept(this, buf); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyShapelessRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyShapelessRecipe.java new file mode 100644 index 000000000..11e26ba43 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyShapelessRecipe.java @@ -0,0 +1,53 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.recipe.CraftingRecipeCategory; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.List; + +@ApiStatus.Obsolete +public class LegacyShapelessRecipe implements LegacyRecipe { + private final List ingredients; + private Item result; + private final String group; + private final CraftingRecipeCategory category; + + public LegacyShapelessRecipe(List ingredients, + Item result, + String group, + CraftingRecipeCategory category) { + this.category = category; + this.ingredients = ingredients; + this.result = result; + this.group = group; + } + + @Override + public void applyClientboundData(Player player) { + this.result = CraftEngine.instance().itemManager().s2c(this.result, player); + for (LegacyIngredient ingredient : this.ingredients) { + ingredient.applyClientboundData(player); + } + } + + public static LegacyShapelessRecipe read(FriendlyByteBuf buf) { + String group = buf.readUtf(); + CraftingRecipeCategory category = CraftingRecipeCategory.byId(buf.readVarInt()); + List ingredient = buf.readCollection(ArrayList::new, LegacyIngredient::read); + Item result = CraftEngine.instance().itemManager().decode(buf); + return new LegacyShapelessRecipe(ingredient, result, group, category); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeUtf(this.group); + buf.writeVarInt(this.category.ordinal()); + buf.writeCollection(this.ingredients, (byteBuf, legacyIngredient) -> legacyIngredient.write(buf)); + CraftEngine.instance().itemManager().encode(buf, this.result); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacySmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacySmithingTransformRecipe.java new file mode 100644 index 000000000..cf9f51314 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacySmithingTransformRecipe.java @@ -0,0 +1,46 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Obsolete +public class LegacySmithingTransformRecipe implements LegacyRecipe { + private final LegacyIngredient template; + private final LegacyIngredient base; + private final LegacyIngredient addition; + private Item result; + + public LegacySmithingTransformRecipe(LegacyIngredient addition, LegacyIngredient template, LegacyIngredient base, Item result) { + this.addition = addition; + this.template = template; + this.base = base; + this.result = result; + } + + @Override + public void applyClientboundData(Player player) { + this.result = CraftEngine.instance().itemManager().s2c(this.result, player); + this.template.applyClientboundData(player); + this.base.applyClientboundData(player); + this.addition.applyClientboundData(player); + } + + public static LegacySmithingTransformRecipe read(FriendlyByteBuf buf) { + LegacyIngredient template = LegacyIngredient.read(buf); + LegacyIngredient base = LegacyIngredient.read(buf); + LegacyIngredient addition = LegacyIngredient.read(buf); + Item result = CraftEngine.instance().itemManager().decode(buf); + return new LegacySmithingTransformRecipe(template, base, addition, result); + } + + @Override + public void write(FriendlyByteBuf buf) { + this.template.write(buf); + this.base.write(buf); + this.addition.write(buf); + CraftEngine.instance().itemManager().encode(buf, this.result); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacySmithingTrimRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacySmithingTrimRecipe.java new file mode 100644 index 000000000..55159bfab --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacySmithingTrimRecipe.java @@ -0,0 +1,39 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Obsolete +public class LegacySmithingTrimRecipe implements LegacyRecipe { + private final LegacyIngredient template; + private final LegacyIngredient base; + private final LegacyIngredient addition; + + public LegacySmithingTrimRecipe(LegacyIngredient addition, LegacyIngredient template, LegacyIngredient base) { + this.addition = addition; + this.template = template; + this.base = base; + } + + @Override + public void applyClientboundData(Player player) { + this.template.applyClientboundData(player); + this.base.applyClientboundData(player); + this.addition.applyClientboundData(player); + } + + public static LegacySmithingTrimRecipe read(FriendlyByteBuf buf) { + LegacyIngredient template = LegacyIngredient.read(buf); + LegacyIngredient base = LegacyIngredient.read(buf); + LegacyIngredient addition = LegacyIngredient.read(buf); + return new LegacySmithingTrimRecipe(template, base, addition); + } + + @Override + public void write(FriendlyByteBuf buf) { + this.template.write(buf); + this.base.write(buf); + this.addition.write(buf); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyStoneCuttingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyStoneCuttingRecipe.java new file mode 100644 index 000000000..e07c6f7d9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/legacy/LegacyStoneCuttingRecipe.java @@ -0,0 +1,42 @@ +package net.momirealms.craftengine.core.item.recipe.network.legacy; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Obsolete +public class LegacyStoneCuttingRecipe implements LegacyRecipe { + private Item result; + private final String group; + private final LegacyIngredient ingredient; + + public LegacyStoneCuttingRecipe(LegacyIngredient ingredient, + Item result, + String group) { + this.ingredient = ingredient; + this.result = result; + this.group = group; + } + + @Override + public void applyClientboundData(Player player) { + this.result = CraftEngine.instance().itemManager().s2c(this.result, player); + this.ingredient.applyClientboundData(player); + } + + public static LegacyStoneCuttingRecipe read(FriendlyByteBuf buf) { + String group = buf.readUtf(); + LegacyIngredient ingredient = LegacyIngredient.read(buf); + Item result = CraftEngine.instance().itemManager().decode(buf); + return new LegacyStoneCuttingRecipe(ingredient, result, group); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeUtf(this.group); + this.ingredient.write(buf); + CraftEngine.instance().itemManager().encode(buf, this.result); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/RecipeBookDisplayEntry.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/RecipeBookDisplayEntry.java new file mode 100644 index 000000000..aab9394ec --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/RecipeBookDisplayEntry.java @@ -0,0 +1,51 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern; + +import com.mojang.datafixers.util.Either; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; + +public record RecipeBookDisplayEntry(RecipeDisplayId displayId, RecipeDisplay display, OptionalInt group, int category, Optional> ingredients) { + + public static RecipeBookDisplayEntry read(FriendlyByteBuf buffer) { + RecipeDisplayId displayId = RecipeDisplayId.read(buffer); + RecipeDisplay display = RecipeDisplay.read(buffer); + OptionalInt group = buffer.readOptionalVarInt(); + int category = buffer.readVarInt(); // simplify the registry lookup since we don't care about the category + Optional> requirements = buffer.readOptional(buf -> buf.readCollection(ArrayList::new, byteBuf -> new Ingredient(byteBuf.readHolderSet()))); // simplify the registry lookup since we don't care about the ingredient ids + return new RecipeBookDisplayEntry(displayId, display, group, category, requirements); + } + + public void applyClientboundData(Player player) { + this.display.applyClientboundData(player); + } + + public void write(FriendlyByteBuf buffer) { + this.displayId.write(buffer); + this.display.write(buffer); + buffer.writeOptionalVarInt(this.group); + buffer.writeVarInt(this.category); + buffer.writeOptional(this.ingredients, (buf, recipeIngredients) -> buf.writeCollection(recipeIngredients, (byteBuf, ingredient) -> byteBuf.writeHolderSet(ingredient.holderSet))); + } + + @Override + public @NotNull String toString() { + return "RecipeBookDisplayEntry{" + + "category=" + category + + ", displayId=" + displayId + + ", display=" + display + + ", group=" + group + + ", ingredients=" + ingredients + + '}'; + } + + public record Ingredient(Either, Key> holderSet) { + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/RecipeBookEntry.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/RecipeBookEntry.java new file mode 100644 index 000000000..ed7706a52 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/RecipeBookEntry.java @@ -0,0 +1,23 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +public record RecipeBookEntry(RecipeBookDisplayEntry entry, byte flags) { + + public void applyClientboundData(Player player) { + this.entry.applyClientboundData(player); + } + + public static RecipeBookEntry read(FriendlyByteBuf buffer) { + RecipeBookDisplayEntry displayEntry = RecipeBookDisplayEntry.read(buffer); + byte flags = buffer.readByte(); + return new RecipeBookEntry(displayEntry, flags); + } + + public void write(FriendlyByteBuf buffer) { + this.entry.write(buffer); + buffer.writeByte(this.flags); + } +} + diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/RecipeDisplayId.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/RecipeDisplayId.java new file mode 100644 index 000000000..90cf9a22e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/RecipeDisplayId.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern; + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.NotNull; + +public record RecipeDisplayId(int id) { + + public void write(FriendlyByteBuf buffer) { + buffer.writeVarInt(this.id); + } + + public static RecipeDisplayId read(FriendlyByteBuf buffer) { + return new RecipeDisplayId(buffer.readVarInt()); + } + + @Override + public @NotNull String toString() { + return "RecipeDisplayId{" + + "id=" + id + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/FurnaceRecipeDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/FurnaceRecipeDisplay.java new file mode 100644 index 000000000..dd3e2f67a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/FurnaceRecipeDisplay.java @@ -0,0 +1,50 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.NotNull; + +public record FurnaceRecipeDisplay(SlotDisplay ingredient, SlotDisplay fuel, SlotDisplay result, SlotDisplay craftingStation, int duration, float experience) implements RecipeDisplay { + + public static FurnaceRecipeDisplay read(FriendlyByteBuf buffer) { + SlotDisplay ingredient = SlotDisplay.read(buffer); + SlotDisplay fuel = SlotDisplay.read(buffer); + SlotDisplay result = SlotDisplay.read(buffer); + SlotDisplay craftingStation = SlotDisplay.read(buffer); + int duration = buffer.readVarInt(); + float experience = buffer.readFloat(); + return new FurnaceRecipeDisplay(ingredient, fuel, result, craftingStation, duration, experience); + } + + @Override + public void applyClientboundData(Player player) { + this.ingredient.applyClientboundData(player); + this.fuel.applyClientboundData(player); + this.result.applyClientboundData(player); + this.craftingStation.applyClientboundData(player); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(2); + this.ingredient.write(buf); + this.fuel.write(buf); + this.result.write(buf); + this.craftingStation.write(buf); + buf.writeVarInt(this.duration); + buf.writeFloat(this.experience); + } + + @Override + public @NotNull String toString() { + return "FurnaceRecipeDisplay{" + + "craftingStation=" + craftingStation + + ", ingredient=" + ingredient + + ", fuel=" + fuel + + ", result=" + result + + ", duration=" + duration + + ", experience=" + experience + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/RecipeDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/RecipeDisplay.java new file mode 100644 index 000000000..0a0713b80 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/RecipeDisplay.java @@ -0,0 +1,25 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.function.Function; + +public interface RecipeDisplay { + + void write(FriendlyByteBuf buf); + + void applyClientboundData(Player player); + + static RecipeDisplay read(final FriendlyByteBuf buf) { + return buf.readById(BuiltInRegistries.RECIPE_DISPLAY_TYPE).read(buf); + } + + record Type(Function reader) { + + public RecipeDisplay read(final FriendlyByteBuf buf) { + return this.reader.apply(buf); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/RecipeDisplayTypes.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/RecipeDisplayTypes.java new file mode 100644 index 000000000..da82d2a0d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/RecipeDisplayTypes.java @@ -0,0 +1,29 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display; + +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceKey; + +public final class RecipeDisplayTypes { + private RecipeDisplayTypes() {} + + public static final Key CRAFTING_SHAPELESS = Key.of("crafting_shapeless"); + public static final Key CRAFTING_SHAPED = Key.of("crafting_shaped"); + public static final Key FURNACE = Key.of("furnace"); + public static final Key STONECUTTER = Key.of("stonecutter"); + public static final Key SMITHING = Key.of("smithing"); + + public static void register() { + register(CRAFTING_SHAPELESS, new RecipeDisplay.Type(ShapelessCraftingRecipeDisplay::read)); + register(CRAFTING_SHAPED, new RecipeDisplay.Type(ShapedCraftingRecipeDisplay::read)); + register(FURNACE, new RecipeDisplay.Type(FurnaceRecipeDisplay::read)); + register(STONECUTTER, new RecipeDisplay.Type(StonecutterRecipeDisplay::read)); + register(SMITHING, new RecipeDisplay.Type(SmithingRecipeDisplay::read)); + } + + public static void register(Key key, RecipeDisplay.Type type) { + ((WritableRegistry) BuiltInRegistries.RECIPE_DISPLAY_TYPE).register(ResourceKey.create(Registries.RECIPE_DISPLAY_TYPE.location(), key), type); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/ShapedCraftingRecipeDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/ShapedCraftingRecipeDisplay.java new file mode 100644 index 000000000..90a7f2a76 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/ShapedCraftingRecipeDisplay.java @@ -0,0 +1,51 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public record ShapedCraftingRecipeDisplay(int width, int height, List ingredients, SlotDisplay result, SlotDisplay craftingStation) implements RecipeDisplay { + + public static ShapedCraftingRecipeDisplay read(FriendlyByteBuf buffer) { + int width = buffer.readVarInt(); + int height = buffer.readVarInt(); + List ingredients = buffer.readCollection(ArrayList::new, SlotDisplay::read); + SlotDisplay result = SlotDisplay.read(buffer); + SlotDisplay craftingStation = SlotDisplay.read(buffer); + return new ShapedCraftingRecipeDisplay(width, height, ingredients, result, craftingStation); + } + + @Override + public void applyClientboundData(Player player) { + for (SlotDisplay ingredient : this.ingredients) { + ingredient.applyClientboundData(player); + } + this.result.applyClientboundData(player); + this.craftingStation.applyClientboundData(player); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(1); + buf.writeVarInt(this.width); + buf.writeVarInt(this.height); + buf.writeCollection(this.ingredients, (byteBuf, slotDisplay) -> slotDisplay.write(buf)); + this.result.write(buf); + this.craftingStation.write(buf); + } + + @Override + public @NotNull String toString() { + return "ShapedCraftingRecipeDisplay{" + + "craftingStation=" + craftingStation + + ", width=" + width + + ", height=" + height + + ", ingredients=" + ingredients + + ", result=" + result + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/ShapelessCraftingRecipeDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/ShapelessCraftingRecipeDisplay.java new file mode 100644 index 000000000..5f776b43b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/ShapelessCraftingRecipeDisplay.java @@ -0,0 +1,45 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public record ShapelessCraftingRecipeDisplay(List ingredients, SlotDisplay result, SlotDisplay craftingStation) implements RecipeDisplay { + + public static ShapelessCraftingRecipeDisplay read(FriendlyByteBuf buffer) { + List ingredients = buffer.readCollection(ArrayList::new, SlotDisplay::read); + SlotDisplay result = SlotDisplay.read(buffer); + SlotDisplay craftingStation = SlotDisplay.read(buffer); + return new ShapelessCraftingRecipeDisplay(ingredients, result, craftingStation); + } + + @Override + public void applyClientboundData(Player player) { + for (SlotDisplay ingredient : ingredients) { + ingredient.applyClientboundData(player); + } + this.result.applyClientboundData(player); + this.craftingStation.applyClientboundData(player); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(0); + buf.writeCollection(this.ingredients, (byteBuf, slotDisplay) -> slotDisplay.write(buf)); + this.result.write(buf); + this.craftingStation.write(buf); + } + + @Override + public @NotNull String toString() { + return "ShapelessCraftingRecipeDisplay{" + + "craftingStation=" + craftingStation + + ", ingredients=" + ingredients + + ", result=" + result + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/SmithingRecipeDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/SmithingRecipeDisplay.java new file mode 100644 index 000000000..e276f06bd --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/SmithingRecipeDisplay.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.NotNull; + +public record SmithingRecipeDisplay(SlotDisplay template, SlotDisplay base, SlotDisplay addition, SlotDisplay result, SlotDisplay craftingStation) implements RecipeDisplay { + + public static SmithingRecipeDisplay read(FriendlyByteBuf buffer) { + SlotDisplay template = SlotDisplay.read(buffer); + SlotDisplay base = SlotDisplay.read(buffer); + SlotDisplay addition = SlotDisplay.read(buffer); + SlotDisplay result = SlotDisplay.read(buffer); + SlotDisplay craftingStation = SlotDisplay.read(buffer); + return new SmithingRecipeDisplay(template, base, addition, result, craftingStation); + } + + @Override + public void applyClientboundData(Player player) { + this.template.applyClientboundData(player); + this.base.applyClientboundData(player); + this.addition.applyClientboundData(player); + this.result.applyClientboundData(player); + this.craftingStation.applyClientboundData(player); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(4); + this.template.write(buf); + this.base.write(buf); + this.addition.write(buf); + this.result.write(buf); + this.craftingStation.write(buf); + } + + @Override + public @NotNull String toString() { + return "SmithingRecipeDisplay{" + + "addition=" + addition + + ", template=" + template + + ", base=" + base + + ", result=" + result + + ", craftingStation=" + craftingStation + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/StonecutterRecipeDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/StonecutterRecipeDisplay.java new file mode 100644 index 000000000..e0281e642 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/StonecutterRecipeDisplay.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import org.jetbrains.annotations.NotNull; + +public record StonecutterRecipeDisplay(SlotDisplay input, SlotDisplay result, SlotDisplay craftingStation) implements RecipeDisplay { + + public static StonecutterRecipeDisplay read(FriendlyByteBuf buffer) { + SlotDisplay input = SlotDisplay.read(buffer); + SlotDisplay result = SlotDisplay.read(buffer); + SlotDisplay craftingStation = SlotDisplay.read(buffer); + return new StonecutterRecipeDisplay(input, result, craftingStation); + } + + @Override + public void applyClientboundData(Player player) { + this.input.applyClientboundData(player); + this.result.applyClientboundData(player); + this.craftingStation.applyClientboundData(player); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(3); + this.input.write(buf); + this.result.write(buf); + this.craftingStation.write(buf); + } + + @Override + public @NotNull String toString() { + return "StonecutterRecipeDisplay{" + + "craftingStation=" + craftingStation + + ", input=" + input + + ", result=" + result + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/AnyFuelDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/AnyFuelDisplay.java new file mode 100644 index 000000000..35ae7cae8 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/AnyFuelDisplay.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display.slot; + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +public class AnyFuelDisplay implements SlotDisplay { + public static final AnyFuelDisplay INSTANCE = new AnyFuelDisplay(); + + public static AnyFuelDisplay read(FriendlyByteBuf buf) { + return INSTANCE; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(1); + } + + @Override + public String toString() { + return "AnyFuelDisplay{}"; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/CompositeSlotDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/CompositeSlotDisplay.java new file mode 100644 index 000000000..2ce54a3af --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/CompositeSlotDisplay.java @@ -0,0 +1,44 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display.slot; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.ArrayList; +import java.util.List; + +public class CompositeSlotDisplay implements SlotDisplay { + private final List slots; + + public CompositeSlotDisplay(List slots) { + this.slots = slots; + } + + public static CompositeSlotDisplay read(FriendlyByteBuf buf) { + List slots = buf.readCollection(ArrayList::new, SlotDisplay::read); + return new CompositeSlotDisplay(slots); + } + + @Override + public void applyClientboundData(Player player) { + for (SlotDisplay slotDisplay : this.slots) { + slotDisplay.applyClientboundData(player); + } + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(7); + buf.writeCollection(this.slots, (byteBuf, slotDisplay) -> slotDisplay.write(buf)); + } + + public List slots() { + return this.slots; + } + + @Override + public String toString() { + return "CompositeSlotDisplay{" + + "slots=" + slots + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/EmptySlotDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/EmptySlotDisplay.java new file mode 100644 index 000000000..90ecf7403 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/EmptySlotDisplay.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display.slot; + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +public class EmptySlotDisplay implements SlotDisplay { + public static final EmptySlotDisplay INSTANCE = new EmptySlotDisplay(); + + public static EmptySlotDisplay read(FriendlyByteBuf buf) { + return INSTANCE; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(0); + } + + @Override + public String toString() { + return "EmptySlotDisplay{}"; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/ItemSlotDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/ItemSlotDisplay.java new file mode 100644 index 000000000..1b5c187ad --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/ItemSlotDisplay.java @@ -0,0 +1,33 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display.slot; + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +public class ItemSlotDisplay implements SlotDisplay { + private final int item; + + public ItemSlotDisplay(int item) { + this.item = item; + } + + public static ItemSlotDisplay read(FriendlyByteBuf buf) { + int item = buf.readVarInt(); + return new ItemSlotDisplay(item); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(2); + buf.writeVarInt(this.item); + } + + public int item() { + return item; + } + + @Override + public String toString() { + return "ItemSlotDisplay{" + + "item=" + item + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/ItemStackSlotDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/ItemStackSlotDisplay.java new file mode 100644 index 000000000..2e449d33d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/ItemStackSlotDisplay.java @@ -0,0 +1,45 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display.slot; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +public class ItemStackSlotDisplay implements SlotDisplay { + private Item item; + + public ItemStackSlotDisplay(Item item) { + this.item = item; + } + + public static ItemStackSlotDisplay read(FriendlyByteBuf buf) { + Item itemStack = CraftEngine.instance().itemManager().decode(buf); + return new ItemStackSlotDisplay(itemStack); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(3); + CraftEngine.instance().itemManager().encode(buf, this.item); + } + + @Override + public void applyClientboundData(Player player) { + this.item = CraftEngine.instance().itemManager().s2c(this.item, player); + } + + public Item item() { + return this.item; + } + + public void setItem(Item item) { + this.item = item; + } + + @Override + public String toString() { + return "ItemStackSlotDisplay{" + + "item=" + this.item.getLiteralObject() + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/SlotDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/SlotDisplay.java new file mode 100644 index 000000000..6a61b1b99 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/SlotDisplay.java @@ -0,0 +1,26 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display.slot; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +import java.util.function.Function; + +public interface SlotDisplay { + + void write(FriendlyByteBuf buf); + + default void applyClientboundData(Player player) { + } + + static SlotDisplay read(FriendlyByteBuf buf) { + return buf.readById(BuiltInRegistries.SLOT_DISPLAY_TYPE).read(buf); + } + + record Type(Function reader) { + + public SlotDisplay read(final FriendlyByteBuf buf) { + return this.reader.apply(buf); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/SlotDisplayTypes.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/SlotDisplayTypes.java new file mode 100644 index 000000000..36e63baf4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/SlotDisplayTypes.java @@ -0,0 +1,36 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display.slot; + +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceKey; + +public final class SlotDisplayTypes { + private SlotDisplayTypes() {} + + public static final Key EMPTY = Key.of("empty"); + public static final Key ANY_FUEL = Key.of("any_fuel"); + public static final Key ITEM = Key.of("item"); + public static final Key ITEM_STACK = Key.of("item_stack"); + public static final Key TAG = Key.of("tag"); + public static final Key SMITHING_TRIM = Key.of("smithing_trim"); + public static final Key WITH_REMAINDER = Key.of("with_remainder"); + public static final Key COMPOSITE = Key.of("composite"); + + public static void register() { + register(EMPTY, new SlotDisplay.Type(EmptySlotDisplay::read)); + register(ANY_FUEL, new SlotDisplay.Type(AnyFuelDisplay::read)); + register(ITEM, new SlotDisplay.Type(ItemSlotDisplay::read)); + register(ITEM_STACK, new SlotDisplay.Type(ItemStackSlotDisplay::read)); + register(TAG, new SlotDisplay.Type(TagSlotDisplay::read)); + register(SMITHING_TRIM, new SlotDisplay.Type(SmithingTrimDemoSlotDisplay::read)); + register(WITH_REMAINDER, new SlotDisplay.Type(WithRemainderSlotDisplay::read)); + register(COMPOSITE, new SlotDisplay.Type(CompositeSlotDisplay::read)); + } + + public static void register(Key key, SlotDisplay.Type type) { + ((WritableRegistry) BuiltInRegistries.SLOT_DISPLAY_TYPE) + .register(ResourceKey.create(Registries.SLOT_DISPLAY_TYPE.location(), key), type); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/SmithingTrimDemoSlotDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/SmithingTrimDemoSlotDisplay.java new file mode 100644 index 000000000..587adf86d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/SmithingTrimDemoSlotDisplay.java @@ -0,0 +1,85 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display.slot; + +import com.mojang.datafixers.util.Either; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.jetbrains.annotations.NotNull; + +public class SmithingTrimDemoSlotDisplay implements SlotDisplay { + private final SlotDisplay base; + private final SlotDisplay material; + // 1.21.2-1.21.4 + private SlotDisplay trimPattern; + // 1.21.5 + private Either either; + + public SmithingTrimDemoSlotDisplay(SlotDisplay base, SlotDisplay material, SlotDisplay trimPattern) { + this.base = base; + this.material = material; + this.trimPattern = trimPattern; + } + + public SmithingTrimDemoSlotDisplay(SlotDisplay base, SlotDisplay material, Either either) { + this.base = base; + this.either = either; + this.material = material; + } + + public static SmithingTrimDemoSlotDisplay read(FriendlyByteBuf buf) { + SlotDisplay base = SlotDisplay.read(buf); + SlotDisplay material = SlotDisplay.read(buf); + if (VersionHelper.isOrAbove1_21_5()) { + Either either = buf.readHolder(byteBuf -> { + Key assetId = buf.readKey(); + Component component = AdventureHelper.nbtToComponent(buf.readNbt(false)); + boolean decal = buf.readBoolean(); + return new TrimPattern(assetId, component, decal); + }); + return new SmithingTrimDemoSlotDisplay(base, material, either); + } else { + SlotDisplay trimPattern = SlotDisplay.read(buf); + return new SmithingTrimDemoSlotDisplay(base, material, trimPattern); + } + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(5); + this.base.write(buf); + this.material.write(buf); + if (VersionHelper.isOrAbove1_21_5()) { + buf.writeHolder(this.either, (byteBuf, pattern) -> { + byteBuf.writeKey(pattern.assetId); + byteBuf.writeNbt(AdventureHelper.componentToNbt(pattern.description), false); + byteBuf.writeBoolean(pattern.decal); + }); + } else { + this.trimPattern.write(buf); + } + } + + @Override + public String toString() { + return "SmithingTrimDemoSlotDisplay{" + + "base=" + base + + ", material=" + material + + ", trimPattern=" + trimPattern + + ", either=" + either + + '}'; + } + + public record TrimPattern(Key assetId, Component description, boolean decal) { + + @Override + public @NotNull String toString() { + return "TrimPattern{" + + "assetId=" + assetId + + ", description=" + description + + ", decal=" + decal + + '}'; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/TagSlotDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/TagSlotDisplay.java new file mode 100644 index 000000000..a6db7c345 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/TagSlotDisplay.java @@ -0,0 +1,29 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display.slot; + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; +import net.momirealms.craftengine.core.util.Key; + +public class TagSlotDisplay implements SlotDisplay { + private final Key tag; + + public TagSlotDisplay(Key tag) { + this.tag = tag; + } + + public static TagSlotDisplay read(FriendlyByteBuf buf) { + return new TagSlotDisplay(buf.readKey()); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(4); + buf.writeKey(this.tag); + } + + @Override + public String toString() { + return "TagSlotDisplay{" + + "tag=" + tag + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/WithRemainderSlotDisplay.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/WithRemainderSlotDisplay.java new file mode 100644 index 000000000..e25583224 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/network/modern/display/slot/WithRemainderSlotDisplay.java @@ -0,0 +1,34 @@ +package net.momirealms.craftengine.core.item.recipe.network.modern.display.slot; + +import net.momirealms.craftengine.core.util.FriendlyByteBuf; + +public class WithRemainderSlotDisplay implements SlotDisplay { + private final SlotDisplay input; + private final SlotDisplay remainder; + + public WithRemainderSlotDisplay(SlotDisplay input, SlotDisplay remainder) { + this.input = input; + this.remainder = remainder; + } + + public static WithRemainderSlotDisplay read(FriendlyByteBuf buf) { + SlotDisplay input = SlotDisplay.read(buf); + SlotDisplay remainder = SlotDisplay.read(buf); + return new WithRemainderSlotDisplay(input, remainder); + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(6); + this.input.write(buf); + this.remainder.write(buf); + } + + @Override + public String toString() { + return "WithRemainderSlotDisplay{" + + "input=" + input + + ", remainder=" + remainder + + '}'; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java index 813a35e34..99d4e9aed 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaGroupedRecipe.java @@ -13,7 +13,6 @@ public abstract class VanillaGroupedRecipe implements VanillaRecipe { return group; } - @Override public RecipeResult result() { return result; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipe.java index d020f5a69..a58cc6523 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipe.java @@ -5,6 +5,4 @@ import net.momirealms.craftengine.core.util.Key; public interface VanillaRecipe { Key type(); - - RecipeResult result(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java index f75e42eea..343d9b06a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaRecipeReader.java @@ -19,4 +19,6 @@ public interface VanillaRecipeReader { VanillaStoneCuttingRecipe readStoneCutting(JsonObject json); VanillaSmithingTransformRecipe readSmithingTransform(JsonObject json); + + VanillaSmithingTrimRecipe readSmithingTrim(JsonObject json); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java index 6ad75f38e..fef4ffbda 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTransformRecipe.java @@ -23,7 +23,6 @@ public class VanillaSmithingTransformRecipe implements VanillaRecipe { return RecipeTypes.SMITHING_TRANSFORM; } - @Override public RecipeResult result() { return result; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java new file mode 100644 index 000000000..4b6bee14d --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/VanillaSmithingTrimRecipe.java @@ -0,0 +1,45 @@ +package net.momirealms.craftengine.core.item.recipe.vanilla; + +import net.momirealms.craftengine.core.item.recipe.RecipeTypes; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class VanillaSmithingTrimRecipe implements VanillaRecipe { + @Nullable // 1.21.5 + private final String pattern; + + private final List base; + private final List template; + private final List addition; + + public VanillaSmithingTrimRecipe(List base, List template, List addition, @Nullable String pattern) { + this.base = base; + this.template = template; + this.addition = addition; + this.pattern = pattern; + } + + @Override + public Key type() { + return RecipeTypes.SMITHING_TRIM; + } + + public List base() { + return base; + } + + public List template() { + return template; + } + + public List addition() { + return addition; + } + + @Nullable + public String pattern() { + return pattern; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20.java index ff836a317..d45c8e5a2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_20.java @@ -101,6 +101,16 @@ public class VanillaRecipeReader1_20 extends AbstractRecipeReader { ); } + @Override + public VanillaSmithingTrimRecipe readSmithingTrim(JsonObject json) { + return new VanillaSmithingTrimRecipe( + readSingleIngredient(json.get("base")), + readSingleIngredient(json.get("template")), + readSingleIngredient(json.get("addition")), + null + ); + } + protected List readSingleIngredient(JsonElement json) { List ingredients = new ArrayList<>(); if (json.isJsonObject()) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_21_5.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_21_5.java new file mode 100644 index 000000000..49634d90e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/vanilla/reader/VanillaRecipeReader1_21_5.java @@ -0,0 +1,17 @@ +package net.momirealms.craftengine.core.item.recipe.vanilla.reader; + +import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaSmithingTrimRecipe; + +public class VanillaRecipeReader1_21_5 extends VanillaRecipeReader1_21_2 { + + @Override + public VanillaSmithingTrimRecipe readSmithingTrim(JsonObject json) { + return new VanillaSmithingTrimRecipe( + readSingleIngredient(json.get("base")), + readSingleIngredient(json.get("template")), + readSingleIngredient(json.get("addition")), + json.get("pattern").getAsString() + ); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java b/core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java index 39e4dfacf..9f49c0b19 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/setting/EquipmentData.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.item.setting; import net.momirealms.craftengine.core.entity.EquipmentSlot; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -44,8 +43,9 @@ public class EquipmentData { public static EquipmentData fromMap(@NotNull final Map data) { String slot = (String) data.get("slot"); if (slot == null) { - throw new LocalizedResourceConfigException("warning.config.item.settings.equippable.missing_slot"); + throw new IllegalArgumentException("slot cannot be null"); } + // todo 重新写判断,不应该支持手部 EquipmentSlot slotEnum = EquipmentSlot.valueOf(slot.toUpperCase(Locale.ENGLISH)); EquipmentData.Builder builder = EquipmentData.builder().slot(slotEnum); if (data.containsKey("asset-id")) { @@ -130,7 +130,7 @@ public class EquipmentData { private boolean swappable = true; private boolean damageOnHurt = true; // 1.21.5+ - private boolean equipOnInteract = true; + private boolean equipOnInteract = false; private Key cameraOverlay; public Builder() {} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/setting/ItemEquipment.java b/core/src/main/java/net/momirealms/craftengine/core/item/setting/ItemEquipment.java index 0341afe7d..05854c47b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/setting/ItemEquipment.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/setting/ItemEquipment.java @@ -1,101 +1,33 @@ package net.momirealms.craftengine.core.item.setting; -import com.google.gson.JsonObject; -import net.momirealms.craftengine.core.pack.misc.EquipmentLayerType; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.item.equipment.Equipment; +import net.momirealms.craftengine.core.util.Tristate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; - public class ItemEquipment { - private final EquipmentData data; - private final EnumMap> layers; + private final Tristate clientBoundModel; + private final Equipment equipment; + private final EquipmentData equipmentData; - public ItemEquipment(EquipmentData data) { - this.data = data; - this.layers = new EnumMap<>(EquipmentLayerType.class); + public ItemEquipment(Tristate clientBoundModel, @Nullable EquipmentData equipmentData, Equipment equipment) { + this.clientBoundModel = clientBoundModel; + this.equipment = equipment; + this.equipmentData = equipmentData; } - public void addLayer(EquipmentLayerType layerType, List layer) { - this.layers.put(layerType, layer); + @NotNull + public Equipment equipment() { + return this.equipment; } - public EnumMap> layers() { - return layers; + @Nullable + public EquipmentData equipmentData() { + return this.equipmentData; } - public EquipmentData data() { - return data; - } - - public record Layer(String texture, DyeableData data, boolean usePlayerTexture) implements Supplier { - - @NotNull - public static List fromConfig(Object obj) { - switch (obj) { - case String texture -> { - return List.of(new Layer(texture, null, false)); - } - case Map map -> { - Map data = MiscUtils.castToMap(map, false); - String texture = data.get("texture").toString(); - return List.of(new Layer(texture, - DyeableData.fromObj(data.get("dyeable")), - ResourceConfigUtils.getAsBoolean(data.getOrDefault("use-player-texture", false), "use-player-texture") - )); - } - case List list -> { - List layers = new ArrayList<>(); - for (Object inner : list) { - layers.addAll(fromConfig(inner)); - } - return layers; - } - case null, default -> { - return List.of(); - } - } - } - - @Override - public JsonObject get() { - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("texture", texture); - if (this.data != null) { - jsonObject.add("dyeable", this.data.get()); - } - if (this.usePlayerTexture) { - jsonObject.addProperty("use_player_texture", true); - } - return jsonObject; - } - - public record DyeableData(@Nullable Integer colorWhenUndyed) implements Supplier { - - public static DyeableData fromObj(Object obj) { - if (obj instanceof Map map) { - Map data = MiscUtils.castToMap(map, false); - if (data.containsKey("color-when-undyed")) { - return new DyeableData(ResourceConfigUtils.getAsInt(data.get("color-when-undyed"), "color-when-undyed")); - } - } - return new DyeableData(null); - } - - @Override - public JsonObject get() { - JsonObject dyeData = new JsonObject(); - if (this.colorWhenUndyed != null) { - dyeData.addProperty("color_when_undyed", this.colorWhenUndyed); - } - return dyeData; - } - } + @NotNull + public Tristate clientBoundModel() { + return clientBoundModel; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java index 0f43e96d8..1336472bd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.condition.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -41,9 +40,8 @@ public class LootConditions { } public static void register(Key key, ConditionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.LOOT_CONDITION_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.LOOT_CONDITION_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry>) BuiltInRegistries.LOOT_CONDITION_FACTORY) + .register(ResourceKey.create(Registries.LOOT_CONDITION_FACTORY.location(), key), factory); } public static Predicate andConditions(List> predicates) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java index 2d27fb6f1..d2d8abaeb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.loot.entry; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -27,9 +26,8 @@ public class LootEntryContainers { } public static void register(Key key, LootEntryContainerFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.LOOT_ENTRY_CONTAINER_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.LOOT_ENTRY_CONTAINER_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry>) BuiltInRegistries.LOOT_ENTRY_CONTAINER_FACTORY) + .register(ResourceKey.create(Registries.LOOT_ENTRY_CONTAINER_FACTORY.location(), key), factory); } public static List> fromMapList(List> mapList) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java index 734322c73..c0475500d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java @@ -1,14 +1,13 @@ package net.momirealms.craftengine.core.loot.function; -import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.*; @@ -81,9 +80,8 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< } public static void register(Key key, FormulaFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.FORMULA_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.FORMULA_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.FORMULA_FACTORY) + .register(ResourceKey.create(Registries.FORMULA_FACTORY.location(), key), factory); } public static Formula fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java index e380bf022..c2233c20f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -30,9 +29,8 @@ public class LootFunctions { } public static void register(Key key, LootFunctionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.LOOT_FUNCTION_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.LOOT_FUNCTION_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry>) BuiltInRegistries.LOOT_FUNCTION_FACTORY) + .register(ResourceKey.create(Registries.LOOT_FUNCTION_FACTORY.location(), key), factory); } public static BiFunction, LootContext, Item> identity() { 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 feb7a9c9f..855c47836 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 @@ -5,16 +5,17 @@ import com.google.common.collect.Multimap; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; import com.google.gson.*; -import dev.dejvokep.boostedyaml.YamlDocument; 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.equipment.ComponentBasedEquipment; +import net.momirealms.craftengine.core.item.equipment.Equipment; +import net.momirealms.craftengine.core.item.equipment.TrimBasedEquipment; 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; import net.momirealms.craftengine.core.pack.host.ResourcePackHosts; import net.momirealms.craftengine.core.pack.host.impl.NoneHost; -import net.momirealms.craftengine.core.pack.misc.Equipment; import net.momirealms.craftengine.core.pack.model.ItemModel; import net.momirealms.craftengine.core.pack.model.LegacyOverridesModel; import net.momirealms.craftengine.core.pack.model.ModernItemModel; @@ -25,6 +26,7 @@ import net.momirealms.craftengine.core.pack.model.rangedisptach.CustomModelDataR import net.momirealms.craftengine.core.pack.obfuscation.ObfA; import net.momirealms.craftengine.core.pack.obfuscation.ResourcePackGenerationException; import net.momirealms.craftengine.core.pack.revision.Revision; +import net.momirealms.craftengine.core.pack.revision.Revisions; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; @@ -65,17 +67,20 @@ public abstract class AbstractPackManager implements PackManager { public static final Map PRESET_ITEMS = new HashMap<>(); public static final Set VANILLA_TEXTURES = new HashSet<>(); public static final Set VANILLA_MODELS = new HashSet<>(); + public static final String NEW_TRIM_MATERIAL = "custom"; + public static final Set ALLOWED_VANILLA_EQUIPMENT = Set.of("chainmail", "diamond", "gold", "iron", "netherite"); 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"}; + private static final byte[] EMPTY_EQUIPMENT_IMAGE; static { - var stream = new ByteArrayOutputStream(); - try { - ImageIO.write(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB), "png", stream); + try (ByteArrayOutputStream stream1 = new ByteArrayOutputStream(); + ByteArrayOutputStream stream2 = new ByteArrayOutputStream()) { + ImageIO.write(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB), "png", stream1); + EMPTY_IMAGE = stream1.toByteArray(); + ImageIO.write(new BufferedImage(64, 32, BufferedImage.TYPE_INT_ARGB), "png", stream2); + EMPTY_EQUIPMENT_IMAGE = stream2.toByteArray(); } catch (IOException e) { - throw new RuntimeException(e); + throw new RuntimeException("Failed to create empty images.", e); } - EMPTY_IMAGE = stream.toByteArray(); } private final CraftEngine plugin; @@ -115,17 +120,10 @@ public abstract class AbstractPackManager implements PackManager { loadInternalData("internal/models/block/_all.json", PRESET_MODELS_BLOCK::put); loadModernItemModel("internal/items/_all.json", PRESET_ITEMS::put); - 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); + + loadInternalList("textures", "", VANILLA_TEXTURES::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))); @@ -213,6 +211,9 @@ public abstract class AbstractPackManager implements PackManager { } TranslationManager.instance().log(e.node(), e.arguments()); this.resourcePackHost = NoneHost.INSTANCE; + } catch (Exception e) { + this.plugin.logger().warn("Failed to load resource pack host", e); + this.resourcePackHost = NoneHost.INSTANCE; } } @@ -317,12 +318,17 @@ 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); - enable = metaYML.getBoolean("enable", true); - namespace = metaYML.getString("namespace", namespace); - description = metaYML.getString("description"); - version = metaYML.getString("version"); - author = metaYML.getString("author"); + Yaml yaml = new Yaml(new StringKeyConstructor(path, new LoaderOptions())); + try (InputStream is = Files.newInputStream(metaFile)) { + Map data = yaml.load(is); + enable = ResourceConfigUtils.getAsBoolean(data.getOrDefault("enable", true), "enable"); + namespace = data.getOrDefault("namespace", namespace).toString(); + description = Optional.ofNullable(data.get("description")).map(String::valueOf).orElse(null); + version = Optional.ofNullable(data.get("version")).map(String::valueOf).orElse(null); + author = Optional.ofNullable(data.get("author")).map(String::valueOf).orElse(null); + } catch (IOException e) { + this.plugin.logger().warn("Failed to load " + metaFile, e); + } } Pack pack = new Pack(path, new PackMeta(author, description, version, namespace), enable); this.loadedPacks.put(path.getFileName().toString(), pack); @@ -341,6 +347,10 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/remove_shulker_head/resourcepack/1_20_5_remove_shulker_head_overlay/minecraft/shaders/core/rendertype_entity_solid.fsh"); plugin.saveResource("resources/remove_shulker_head/resourcepack/assets/minecraft/textures/entity/shulker/shulker_white.png"); plugin.saveResource("resources/remove_shulker_head/pack.yml"); + plugin.saveResource("resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid/chainmail.png"); + plugin.saveResource("resources/legacy_armor/resourcepack/assets/minecraft/textures/trims/entity/humanoid_leggings/chainmail.png"); + plugin.saveResource("resources/legacy_armor/configuration/chainmail.yml"); + plugin.saveResource("resources/legacy_armor/pack.yml"); plugin.saveResource("resources/internal/pack.yml"); // i18n plugin.saveResource("resources/internal/configuration/i18n.yml"); @@ -552,6 +562,7 @@ public abstract class AbstractPackManager implements PackManager { ConfigParser parser = entry.getKey(); if (!predicate.test(parser)) continue; long t1 = System.nanoTime(); + parser.preProcess(); for (CachedConfigSection cached : entry.getValue()) { for (Map.Entry configEntry : cached.config().entrySet()) { String key = configEntry.getKey(); @@ -579,12 +590,12 @@ public abstract class AbstractPackManager implements PackManager { exception.setId(cached.prefix() + "." + key); } 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. Additional info: " + GsonHelper.get().toJson(configEntry.getValue()), e); } } } + parser.postProcess(); long t2 = System.nanoTime(); this.plugin.logger().info("Loaded " + parser.sectionId()[0] + " in " + String.format("%.2f", ((t2 - t1) / 1_000_000.0)) + " ms"); } @@ -605,7 +616,7 @@ public abstract class AbstractPackManager implements PackManager { @Override public void generateResourcePack() throws IOException { this.plugin.logger().info("Generating resource pack..."); - long start = System.currentTimeMillis(); + long time1 = System.currentTimeMillis(); // get the target location try (FileSystem fs = Jimfs.newFileSystem(Configuration.forCurrentPlatform())) { @@ -632,22 +643,27 @@ public abstract class AbstractPackManager implements PackManager { this.generateItemModels(generatedPackPath, this.plugin.itemManager()); this.generateItemModels(generatedPackPath, this.plugin.blockManager()); this.generateBlockOverrides(generatedPackPath); - this.generateLegacyItemOverrides(generatedPackPath); - this.generateModernItemOverrides(generatedPackPath, revisions::add); + // 一定要先生成item-model再生成overrides this.generateModernItemModels1_21_2(generatedPackPath); this.generateModernItemModels1_21_4(generatedPackPath, revisions::add); + this.generateLegacyItemOverrides(generatedPackPath); + this.generateModernItemOverrides(generatedPackPath, revisions::add); this.generateOverrideSounds(generatedPackPath); this.generateCustomSounds(generatedPackPath); this.generateClientLang(generatedPackPath); - this.generateEquipments(generatedPackPath); + this.generateEquipments(generatedPackPath, revisions::add); this.generateParticle(generatedPackPath); this.generatePackMetadata(generatedPackPath.resolve("pack.mcmeta"), revisions); if (Config.excludeShaders()) { this.removeAllShaders(generatedPackPath); } + long time2 = System.currentTimeMillis(); + this.plugin.logger().info("Generated resource pack in " + (time2 - time1) + "ms"); if (Config.validateResourcePack()) { this.validateResourcePack(generatedPackPath); } + long time3 = System.currentTimeMillis(); + this.plugin.logger().info("Validated resource pack in " + (time3 - time2) + "ms"); Path finalPath = resourcePackPath(); Files.createDirectories(finalPath.getParent()); try { @@ -655,8 +671,8 @@ public abstract class AbstractPackManager implements PackManager { } catch (Exception e) { this.plugin.logger().severe("Error zipping resource pack", e); } - long end = System.currentTimeMillis(); - this.plugin.logger().info("Finished generating resource pack in " + (end - start) + "ms"); + long time4 = System.currentTimeMillis(); + this.plugin.logger().info("Created resource pack zip file in " + (time4 - time3) + "ms"); this.eventDispatcher.accept(generatedPackPath, finalPath); } } @@ -730,7 +746,7 @@ public abstract class AbstractPackManager implements PackManager { } } - private void processAtlas(JsonObject atlasJsonObject, BiConsumer directory, Consumer unstitch, Consumer included) { + private void processAtlas(JsonObject atlasJsonObject, BiConsumer directory, Consumer existing, Consumer included) { JsonArray sources = atlasJsonObject.getAsJsonArray("sources"); if (sources != null) { for (JsonElement source : sources) { @@ -759,7 +775,7 @@ public abstract class AbstractPackManager implements PackManager { if (!(region instanceof JsonObject regionJson)) continue; JsonElement sprite = regionJson.get("sprite"); if (sprite == null) continue; - unstitch.accept(Key.of(sprite.getAsString())); + existing.accept(Key.of(sprite.getAsString())); } } } @@ -776,7 +792,7 @@ public abstract class AbstractPackManager implements PackManager { for (JsonElement texture : textures) { if (!(texture instanceof JsonPrimitive texturePath)) continue; for (String permutation : permutations) { - included.accept(Key.of(texturePath.getAsString() + separator + permutation)); + existing.accept(Key.of(texturePath.getAsString() + separator + permutation)); } } } @@ -787,26 +803,28 @@ public abstract class AbstractPackManager implements PackManager { @SuppressWarnings("DuplicatedCode") private void validateResourcePack(Path path) { - List rootPaths; + Path[] rootPaths; try { - rootPaths = FileUtils.collectOverlays(path); + rootPaths = FileUtils.collectOverlays(path).toArray(new Path[0]); } catch (IOException e) { plugin.logger().warn("Failed to collect overlays for " + path.toAbsolutePath(), e); return; } + Multimap imageToFonts = ArrayListMultimap.create(); // 图片到字体的映射 Multimap modelToItems = ArrayListMultimap.create(); // 模型到物品的映射 Multimap modelToBlocks = ArrayListMultimap.create(); // 模型到方块的映射 - Multimap imageToModels = ArrayListMultimap.create(); // 图片到模型的映射 + Multimap imageToModels = ArrayListMultimap.create(); // 纹理到模型的映射 + Set collectedModels = new HashSet<>(); + Set texturesInAtlas = new HashSet<>(); - Set unstitchTextures = new HashSet<>(); + Set existingTextures = new HashSet<>(VANILLA_TEXTURES); Map directoryMapper = new HashMap<>(); - processAtlas(this.vanillaAtlas, directoryMapper::put, unstitchTextures::add, texturesInAtlas::add); + processAtlas(this.vanillaAtlas, directoryMapper::put, existingTextures::add, texturesInAtlas::add); for (Path rootPath : rootPaths) { Path assetsPath = rootPath.resolve("assets"); if (!Files.isDirectory(assetsPath)) continue; - List namespaces; try { namespaces = FileUtils.collectNamespaces(assetsPath); @@ -819,7 +837,7 @@ public abstract class AbstractPackManager implements PackManager { if (Files.exists(atlasesFile)) { try { JsonObject atlasJsonObject = GsonHelper.readJsonFile(atlasesFile).getAsJsonObject(); - processAtlas(atlasJsonObject, directoryMapper::put, unstitchTextures::add, texturesInAtlas::add); + processAtlas(atlasJsonObject, directoryMapper::put, existingTextures::add, texturesInAtlas::add); } catch (IOException | JsonParseException e) { TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", atlasesFile.toAbsolutePath().toString()); } @@ -915,6 +933,7 @@ public abstract class AbstractPackManager implements PackManager { } } + // 验证font的贴图是否存在 label: for (Map.Entry> entry : imageToFonts.asMap().entrySet()) { Key key = entry.getKey(); if (VANILLA_TEXTURES.contains(key)) continue; @@ -927,31 +946,35 @@ public abstract class AbstractPackManager implements PackManager { 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; + Key modelResourceLocation = entry.getKey(); + boolean alreadyChecked = !collectedModels.add(modelResourceLocation); + if (alreadyChecked || VANILLA_MODELS.contains(modelResourceLocation)) continue; + String modelPath = "assets/" + modelResourceLocation.namespace() + "/models/" + modelResourceLocation.value() + ".json"; for (Path rootPath : rootPaths) { Path modelJsonPath = rootPath.resolve(modelPath); if (Files.exists(rootPath.resolve(modelPath))) { - JsonObject jsonObject; + JsonObject modelJson; try { - jsonObject = GsonHelper.readJsonFile(modelJsonPath).getAsJsonObject(); + modelJson = GsonHelper.readJsonFile(modelJsonPath).getAsJsonObject(); } catch (IOException | JsonParseException e) { TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", modelJsonPath.toAbsolutePath().toString()); continue; } - collectModels(key, jsonObject, rootPaths, imageToModels); + verifyParentModelAndCollectTextures(modelResourceLocation, modelJson, rootPaths, imageToModels, collectedModels); 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; + Key modelResourceLocation = entry.getKey(); + boolean alreadyChecked = !collectedModels.add(modelResourceLocation); + if (alreadyChecked || VANILLA_MODELS.contains(modelResourceLocation)) continue; + String modelPath = "assets/" + modelResourceLocation.namespace() + "/models/" + modelResourceLocation.value() + ".json"; for (Path rootPath : rootPaths) { Path modelJsonPath = rootPath.resolve(modelPath); if (Files.exists(modelJsonPath)) { @@ -962,19 +985,19 @@ public abstract class AbstractPackManager implements PackManager { TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", modelJsonPath.toAbsolutePath().toString()); continue; } - collectModels(key, jsonObject, rootPaths, imageToModels); + verifyParentModelAndCollectTextures(modelResourceLocation, jsonObject, rootPaths, imageToModels, collectedModels); continue label; } } TranslationManager.instance().log("warning.config.resource_pack.generation.missing_block_model", entry.getValue().stream().distinct().toList().toString(), modelPath); } + // 验证贴图是否存在 boolean enableObf = Config.enableObfuscation() && Config.enableRandomResourceLocation(); label: for (Map.Entry> entry : imageToModels.asMap().entrySet()) { Key key = entry.getKey(); - if (VANILLA_TEXTURES.contains(key)) continue; - // 已经拆散的贴图,直接包含 - if (unstitchTextures.contains(key)) continue; + // 已经存在的贴图,直接过滤 + if (existingTextures.contains(key)) continue; // 直接在single中被指定的贴图,只检测是否存在 if (enableObf || texturesInAtlas.contains(key)) { String imagePath = "assets/" + key.namespace() + "/textures/" + key.value() + ".png"; @@ -1003,10 +1026,10 @@ public abstract class AbstractPackManager implements PackManager { } } - private void collectModels(Key model, JsonObject modelJson, List rootPaths, Multimap imageToModels) { - if (modelJson.has("parent")) { - Key parentResourceLocation = Key.from(modelJson.get("parent").getAsString()); - if (!VANILLA_MODELS.contains(parentResourceLocation)) { + private void verifyParentModelAndCollectTextures(Key sourceModelLocation, JsonObject sourceModelJson, Path[] rootPaths, Multimap imageToModels, Set collected) { + if (sourceModelJson.has("parent")) { + Key parentResourceLocation = Key.from(sourceModelJson.get("parent").getAsString()); + if (collected.add(parentResourceLocation) && !VANILLA_MODELS.contains(parentResourceLocation)) { String parentModelPath = "assets/" + parentResourceLocation.namespace() + "/models/" + parentResourceLocation.value() + ".json"; label: { for (Path rootPath : rootPaths) { @@ -1019,21 +1042,21 @@ public abstract class AbstractPackManager implements PackManager { TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", modelJsonPath.toAbsolutePath().toString()); break label; } - collectModels(parentResourceLocation, jsonObject, rootPaths, imageToModels); + verifyParentModelAndCollectTextures(parentResourceLocation, jsonObject, rootPaths, imageToModels, collected); break label; } } - TranslationManager.instance().log("warning.config.resource_pack.generation.missing_parent_model", model.asString(), parentModelPath); + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_parent_model", sourceModelLocation.asString(), parentModelPath); } } } - if (modelJson.has("textures")) { - JsonObject textures = modelJson.get("textures").getAsJsonObject(); + if (sourceModelJson.has("textures")) { + JsonObject textures = sourceModelJson.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); + imageToModels.put(textureResourceLocation, sourceModelLocation); } } } @@ -1144,77 +1167,385 @@ public abstract class AbstractPackManager implements PackManager { } } - private void generateEquipments(Path generatedPackPath) { - for (Map.Entry entry : this.plugin.itemManager().equipmentsToGenerate().entrySet()) { - Key assetId = entry.getKey(); - if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_4)) { - Path equipmentPath = generatedPackPath - .resolve("assets") - .resolve(assetId.namespace()) - .resolve("equipment") - .resolve(assetId.value() + ".json"); + private void generateEquipments(Path generatedPackPath, Consumer callback) { + // asset id + 是否有上身 + 是否有腿 + List> collectedTrims = new ArrayList<>(); - JsonObject equipmentJson = null; - if (Files.exists(equipmentPath)) { - try (BufferedReader reader = Files.newBufferedReader(equipmentPath)) { - equipmentJson = JsonParser.parseReader(reader).getAsJsonObject(); - } catch (IOException e) { - plugin.logger().warn("Failed to load existing sounds.json", e); - return; - } - } - if (equipmentJson != null) { - equipmentJson = GsonHelper.deepMerge(equipmentJson, entry.getValue().get()); - } else { - equipmentJson = entry.getValue().get(); - } - try { - Files.createDirectories(equipmentPath.getParent()); - } catch (IOException e) { - plugin.logger().severe("Error creating " + equipmentPath.toAbsolutePath()); - return; - } - try { - GsonHelper.writeJsonFile(equipmentJson, equipmentPath); - } catch (IOException e) { - this.plugin.logger().severe("Error writing equipment file", e); - } - } - if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2) && Config.packMinVersion().isBelow(MinecraftVersions.V1_21_4)) { - Path equipmentPath = generatedPackPath - .resolve("assets") - .resolve(assetId.namespace()) - .resolve("models") - .resolve("equipment") - .resolve(assetId.value() + ".json"); + // 为trim类型提供的两个兼容性值 + boolean needLegacyCompatibility = Config.packMinVersion().isBelow(MinecraftVersions.V1_21_2); + boolean needModernCompatibility = Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2); - JsonObject equipmentJson = null; - if (Files.exists(equipmentPath)) { - try (BufferedReader reader = Files.newBufferedReader(equipmentPath)) { - equipmentJson = JsonParser.parseReader(reader).getAsJsonObject(); - } catch (IOException e) { - plugin.logger().warn("Failed to load existing sounds.json", e); - return; - } - } - if (equipmentJson != null) { - equipmentJson = GsonHelper.deepMerge(equipmentJson, entry.getValue().get()); - } else { - equipmentJson = entry.getValue().get(); - } - try { - Files.createDirectories(equipmentPath.getParent()); - } catch (IOException e) { - plugin.logger().severe("Error creating " + equipmentPath.toAbsolutePath()); - return; - } - try { - GsonHelper.writeJsonFile(equipmentJson, equipmentPath); - } catch (IOException e) { - this.plugin.logger().severe("Error writing equipment file", e); + for (Equipment equipment : this.plugin.itemManager().equipments().values()) { + if (equipment instanceof ComponentBasedEquipment componentBasedEquipment) { + // 现代的盔甲生成 + processComponentBasedEquipment(componentBasedEquipment, generatedPackPath); + } else if (equipment instanceof TrimBasedEquipment trimBasedEquipment) { + Key assetId = trimBasedEquipment.assetId(); + Pair result = processTrimBasedEquipment(trimBasedEquipment, generatedPackPath); + if (result != null) { + collectedTrims.add(Tuple.of(assetId, result.left(), result.right())); } } } + + if (!collectedTrims.isEmpty()) { + // 获取基础atlas路径 + Path atlasPath = generatedPackPath + .resolve("assets") + .resolve("minecraft") + .resolve("atlases") + .resolve("armor_trims.json"); + // 读取先前sources内容 + JsonArray previousAtlasSources = null; + if (Files.exists(atlasPath) && Files.isRegularFile(atlasPath)) { + try { + previousAtlasSources = GsonHelper.readJsonFile(atlasPath).getAsJsonObject().getAsJsonArray("sources"); + } catch (Exception ignored) { + } + } + + // 修复被干碎的原版盔甲 + Key vanillaFixTrimType = Key.of("minecraft", Config.sacrificedVanillaArmorType()); + collectedTrims.add(Tuple.of(vanillaFixTrimType, true, true)); + processTrimBasedEquipment(new TrimBasedEquipment(vanillaFixTrimType, Config.sacrificedHumanoid(), Config.sacrificedHumanoidLeggings()), generatedPackPath); + + // 准备新版本atlas和覆盖纹理 + JsonObject modernTrimAtlasJson = null; + if (needModernCompatibility) { + modernTrimAtlasJson = new JsonObject(); + JsonArray sourcesArray = new JsonArray(); + modernTrimAtlasJson.add("sources", sourcesArray); + for (Tuple tuple : collectedTrims) { + if (tuple.mid()) { + JsonObject single1 = new JsonObject(); + single1.addProperty("type", "single"); + single1.addProperty("resource", tuple.left().namespace() + ":trims/entity/humanoid/" + tuple.left().value() + "_" + NEW_TRIM_MATERIAL); + sourcesArray.add(single1); + } + if (tuple.right()) { + JsonObject single2 = new JsonObject(); + single2.addProperty("type", "single"); + single2.addProperty("resource", tuple.left().namespace() + ":trims/entity/humanoid_leggings/" + tuple.left().value() + "_" + NEW_TRIM_MATERIAL); + sourcesArray.add(single2); + } + } + if (previousAtlasSources != null) { + sourcesArray.addAll(previousAtlasSources); + } + Path vanillaArmorPath1 = generatedPackPath + .resolve("assets") + .resolve("minecraft") + .resolve("textures") + .resolve("entity") + .resolve("equipment") + .resolve("humanoid") + .resolve(Config.sacrificedVanillaArmorType() + ".png"); + Path vanillaArmorPath2 = generatedPackPath + .resolve("assets") + .resolve("minecraft") + .resolve("textures") + .resolve("entity") + .resolve("equipment") + .resolve("humanoid_leggings") + .resolve(Config.sacrificedVanillaArmorType() + ".png"); + try { + Files.createDirectories(vanillaArmorPath1.getParent()); + Files.createDirectories(vanillaArmorPath2.getParent()); + Files.write(vanillaArmorPath1, EMPTY_EQUIPMENT_IMAGE); + Files.write(vanillaArmorPath2, EMPTY_EQUIPMENT_IMAGE); + } catch (IOException e) { + this.plugin.logger().warn("Failed to write empty vanilla armor texture file", e); + } + } + + // 准备旧版本atlas和覆盖纹理 + JsonObject legacyTrimAtlasJson = null; + if (needLegacyCompatibility) { + legacyTrimAtlasJson = new JsonObject(); + JsonArray sourcesArray = new JsonArray(); + legacyTrimAtlasJson.add("sources", sourcesArray); + for (Tuple tuple : collectedTrims) { + if (tuple.mid()) { + JsonObject single1 = new JsonObject(); + single1.addProperty("type", "single"); + single1.addProperty("resource", tuple.left().namespace() + ":trims/models/armor/" + tuple.left().value() + "_" + NEW_TRIM_MATERIAL); + sourcesArray.add(single1); + } + if (tuple.right()) { + JsonObject single2 = new JsonObject(); + single2.addProperty("type", "single"); + single2.addProperty("resource", tuple.left().namespace() + ":trims/models/armor/" + tuple.left().value() + "_leggings_" + NEW_TRIM_MATERIAL); + sourcesArray.add(single2); + } + } + if (previousAtlasSources != null) { + sourcesArray.addAll(previousAtlasSources); + } + Path vanillaArmorPath1 = generatedPackPath + .resolve("assets") + .resolve("minecraft") + .resolve("textures") + .resolve("models") + .resolve("armor") + .resolve(Config.sacrificedVanillaArmorType() + "_layer_1.png"); + Path vanillaArmorPath2 = generatedPackPath + .resolve("assets") + .resolve("minecraft") + .resolve("textures") + .resolve("models") + .resolve("armor") + .resolve(Config.sacrificedVanillaArmorType() + "_layer_2.png"); + try { + Files.createDirectories(vanillaArmorPath1.getParent()); + Files.write(vanillaArmorPath1, EMPTY_EQUIPMENT_IMAGE); + Files.write(vanillaArmorPath2, EMPTY_EQUIPMENT_IMAGE); + } catch (IOException e) { + this.plugin.logger().warn("Failed to write empty vanilla armor texture file", e); + } + } + // 创建atlas文件夹 + try { + Files.createDirectories(atlasPath.getParent()); + } catch (IOException e) { + this.plugin.logger().severe("Error creating " + atlasPath.toAbsolutePath(), e); + return; + } + // 写入atlas文件 + try (BufferedWriter writer = Files.newBufferedWriter(atlasPath)) { + JsonObject selected = needLegacyCompatibility ? legacyTrimAtlasJson : modernTrimAtlasJson; + // 优先写入旧版 + GsonHelper.get().toJson(selected, writer); + } catch (IOException e) { + this.plugin.logger().severe("Error writing " + atlasPath.toAbsolutePath(), e); + } + // 既要又要,那么需要overlay + if (needLegacyCompatibility && needModernCompatibility) { + Revision revision = Revisions.SINCE_1_21_2; + callback.accept(revision); + Path overlayAtlasPath = generatedPackPath + .resolve(Config.createOverlayFolderName(revision.versionString())) + .resolve("assets") + .resolve("minecraft") + .resolve("atlases") + .resolve("armor_trims.json"); + // 创建atlas文件夹 + try { + Files.createDirectories(overlayAtlasPath.getParent()); + } catch (IOException e) { + this.plugin.logger().severe("Error creating " + overlayAtlasPath.toAbsolutePath(), e); + return; + } + // 写入atlas文件 + try (BufferedWriter writer = Files.newBufferedWriter(overlayAtlasPath)) { + GsonHelper.get().toJson(modernTrimAtlasJson, writer); + callback.accept(revision); + } catch (IOException e) { + this.plugin.logger().severe("Error writing " + overlayAtlasPath.toAbsolutePath(), e); + } + } + } + } + + private void processComponentBasedEquipment(ComponentBasedEquipment componentBasedEquipment, Path generatedPackPath) { + Key assetId = componentBasedEquipment.assetId(); + if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_4)) { + Path equipmentPath = generatedPackPath + .resolve("assets") + .resolve(assetId.namespace()) + .resolve("equipment") + .resolve(assetId.value() + ".json"); + + JsonObject equipmentJson = null; + if (Files.exists(equipmentPath)) { + try (BufferedReader reader = Files.newBufferedReader(equipmentPath)) { + equipmentJson = JsonParser.parseReader(reader).getAsJsonObject(); + } catch (IOException e) { + plugin.logger().warn("Failed to load existing sounds.json", e); + return; + } + } + if (equipmentJson != null) { + equipmentJson = GsonHelper.deepMerge(equipmentJson, componentBasedEquipment.get()); + } else { + equipmentJson = componentBasedEquipment.get(); + } + try { + Files.createDirectories(equipmentPath.getParent()); + } catch (IOException e) { + plugin.logger().severe("Error creating " + equipmentPath.toAbsolutePath()); + return; + } + try { + GsonHelper.writeJsonFile(equipmentJson, equipmentPath); + } catch (IOException e) { + this.plugin.logger().severe("Error writing equipment file", e); + } + } + if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2) && Config.packMinVersion().isBelow(MinecraftVersions.V1_21_4)) { + Path equipmentPath = generatedPackPath + .resolve("assets") + .resolve(assetId.namespace()) + .resolve("models") + .resolve("equipment") + .resolve(assetId.value() + ".json"); + + JsonObject equipmentJson = null; + if (Files.exists(equipmentPath)) { + try (BufferedReader reader = Files.newBufferedReader(equipmentPath)) { + equipmentJson = JsonParser.parseReader(reader).getAsJsonObject(); + } catch (IOException e) { + plugin.logger().warn("Failed to load existing sounds.json", e); + return; + } + } + if (equipmentJson != null) { + equipmentJson = GsonHelper.deepMerge(equipmentJson, componentBasedEquipment.get()); + } else { + equipmentJson = componentBasedEquipment.get(); + } + try { + Files.createDirectories(equipmentPath.getParent()); + } catch (IOException e) { + plugin.logger().severe("Error creating " + equipmentPath.toAbsolutePath()); + return; + } + try { + GsonHelper.writeJsonFile(equipmentJson, equipmentPath); + } catch (IOException e) { + this.plugin.logger().severe("Error writing equipment file", e); + } + } + } + + @Nullable + private Pair processTrimBasedEquipment(TrimBasedEquipment trimBasedEquipment, Path generatedPackPath) { + Key assetId = trimBasedEquipment.assetId(); + + Key humanoidResourceLocation = trimBasedEquipment.humanoid(); + boolean hasLayer1 = humanoidResourceLocation != null; + Key humanoidLeggingsResourceLocation = trimBasedEquipment.humanoidLeggings(); + boolean hasLayer2 = humanoidLeggingsResourceLocation != null; + + if (hasLayer1) { + Path texture = generatedPackPath + .resolve("assets") + .resolve(humanoidResourceLocation.namespace()) + .resolve("textures") + .resolve(humanoidResourceLocation.value() + ".png"); + if (!Files.exists(texture) || !Files.isRegularFile(texture)) { + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_equipment_texture", assetId.asString(), texture.toString()); + return null; + } + boolean shouldPreserve = false; + if (Config.packMinVersion().isBelow(MinecraftVersions.V1_21_2)) { + Path legacyTarget = generatedPackPath + .resolve("assets") + .resolve(assetId.namespace()) + .resolve("textures") + .resolve("trims") + .resolve("models") + .resolve("armor") + .resolve(assetId.value() + "_" + NEW_TRIM_MATERIAL + ".png"); + if (!legacyTarget.equals(texture)) { + try { + Files.createDirectories(legacyTarget.getParent()); + Files.copy(texture, legacyTarget, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + plugin.logger().severe("Error writing armor texture file from " + texture + " to " + legacyTarget, e); + } + } else { + shouldPreserve = true; + } + } + if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2)) { + Path modernTarget = generatedPackPath + .resolve("assets") + .resolve(assetId.namespace()) + .resolve("textures") + .resolve("trims") + .resolve("entity") + .resolve("humanoid") + .resolve(assetId.value() + "_" + NEW_TRIM_MATERIAL + ".png"); + if (!modernTarget.equals(texture)) { + try { + Files.createDirectories(modernTarget.getParent()); + Files.copy(texture, modernTarget, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + plugin.logger().severe("Error writing armor texture file from " + texture + " to " + modernTarget, e); + } + } else { + shouldPreserve = true; + } + } + if (!shouldPreserve) { + try { + Files.delete(texture); + } catch (IOException e) { + this.plugin.logger().severe("Error deleting armor texture file from " + texture, e); + } + } + } + if (hasLayer2) { + Path texture = generatedPackPath + .resolve("assets") + .resolve(humanoidLeggingsResourceLocation.namespace()) + .resolve("textures") + .resolve(humanoidLeggingsResourceLocation.value() + ".png"); + if (!Files.exists(texture) && !Files.isRegularFile(texture)) { + TranslationManager.instance().log("warning.config.resource_pack.generation.missing_equipment_texture", assetId.asString(), texture.toString()); + return null; + } + boolean shouldPreserve = false; + if (Config.packMinVersion().isBelow(MinecraftVersions.V1_21_2)) { + Path legacyTarget = generatedPackPath + .resolve("assets") + .resolve(assetId.namespace()) + .resolve("textures") + .resolve("trims") + .resolve("models") + .resolve("armor") + .resolve(assetId.value() + "_leggings_" + NEW_TRIM_MATERIAL + ".png"); + if (!legacyTarget.equals(texture)) { + try { + Files.createDirectories(legacyTarget.getParent()); + Files.copy(texture, legacyTarget, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + this.plugin.logger().severe("Error writing armor texture file from " + texture + " to " + legacyTarget, e); + } + } else { + shouldPreserve = true; + } + } + if (Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2)) { + Path modernTarget = generatedPackPath + .resolve("assets") + .resolve(assetId.namespace()) + .resolve("textures") + .resolve("trims") + .resolve("entity") + .resolve("humanoid_leggings") + .resolve(assetId.value() + "_" + NEW_TRIM_MATERIAL + ".png"); + if (!modernTarget.equals(texture)) { + try { + Files.createDirectories(modernTarget.getParent()); + Files.copy(texture, modernTarget, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + this.plugin.logger().severe("Error writing armor texture file from " + texture + " to " + modernTarget, e); + } + } else { + shouldPreserve = true; + } + } + if (!shouldPreserve) { + try { + Files.delete(texture); + } catch (IOException e) { + this.plugin.logger().severe("Error deleting armor texture file from " + texture, e); + } + } + } + + return Pair.of(hasLayer1, hasLayer2); } private void generateClientLang(Path generatedPackPath) { @@ -1439,12 +1770,6 @@ public abstract class AbstractPackManager implements PackManager { Key itemModelPath = entry.getKey(); TreeSet legacyOverridesModels = entry.getValue(); - // 检测item model合法性 - if (PRESET_MODERN_MODELS_ITEM.containsKey(itemModelPath) || PRESET_LEGACY_MODELS_ITEM.containsKey(itemModelPath)) { - TranslationManager.instance().log("warning.config.resource_pack.item_model.conflict.vanilla", itemModelPath.asString()); - continue; - } - // 要检查目标生成路径是否已经存在模型,如果存在模型,应该只为其生成overrides Path itemPath = generatedPackPath .resolve("assets") @@ -1506,11 +1831,6 @@ public abstract class AbstractPackManager implements PackManager { .resolve(key.namespace()) .resolve("items") .resolve(key.value() + ".json"); - - if (PRESET_ITEMS.containsKey(key)) { - TranslationManager.instance().log("warning.config.resource_pack.item_model.conflict.vanilla", key.asString()); - continue; - } if (Files.exists(itemPath)) { TranslationManager.instance().log("warning.config.resource_pack.item_model.already_exist", key.asString(), itemPath.toAbsolutePath().toString()); continue; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java b/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java index 496ce89e6..82604386c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/LoadingSequence.java @@ -8,14 +8,15 @@ public final class LoadingSequence { public static final int LANG = 20; public static final int TRANSLATION = 30; public static final int BLOCK = 40; - public static final int ITEM = 50; - public static final int FURNITURE = 60; - public static final int IMAGE = 70; - public static final int RECIPE = 80; - public static final int CATEGORY = 90; - public static final int SOUND = 100; - public static final int JUKEBOX_SONG = 110; - public static final int VANILLA_LOOTS = 120; - public static final int EMOJI = 130; - public static final int ADVANCEMENT = 140; + public static final int EQUIPMENT = 50; + public static final int ITEM = 60; + public static final int FURNITURE = 70; + public static final int IMAGE = 80; + public static final int RECIPE = 90; + public static final int CATEGORY = 100; + public static final int SOUND = 110; + public static final int JUKEBOX_SONG = 120; + public static final int VANILLA_LOOTS = 130; + public static final int EMOJI = 140; + public static final int ADVANCEMENT = 150; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatchers.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatchers.java index 7bffb8178..c3674f5c0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatchers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/matcher/PathMatchers.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.condition.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -37,9 +36,8 @@ public class PathMatchers { } public static void register(Key key, ConditionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PATH_MATCHER_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.PATH_MATCHER_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry>) BuiltInRegistries.PATH_MATCHER_FACTORY) + .register(ResourceKey.create(Registries.PATH_MATCHER_FACTORY.location(), key), factory); } public static List> fromMapList(List> arguments) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java index b80302a07..9d16ffa7d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/Resolutions.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.pack.conflict.resolution; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -27,8 +26,7 @@ public class Resolutions { } public static void register(Key key, ResolutionFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.RESOLUTION_FACTORY).registerForHolder(new ResourceKey<>(Registries.RESOLUTION_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.RESOLUTION_FACTORY).register(ResourceKey.create(Registries.RESOLUTION_FACTORY.location(), key), factory); } public static Resolution fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java index 3c88658fd..8d754cd62 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.pack.host; import net.momirealms.craftengine.core.pack.host.impl.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -35,9 +34,8 @@ public class ResourcePackHosts { } public static void register(Key key, ResourcePackHostFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.RESOURCE_PACK_HOST_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.RESOURCE_PACK_HOST_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.RESOURCE_PACK_HOST_FACTORY) + .register(ResourceKey.create(Registries.RESOURCE_PACK_HOST_FACTORY.location(), key), factory); } public static ResourcePackHost fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java index 74abddf6a..674fbf908 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java @@ -77,17 +77,14 @@ public class AlistHost implements ResourcePackHost { } private void readCacheFromDisk() { - Path cachePath = CraftEngine.instance().dataFolderPath().resolve("alist.cache"); - if (!Files.exists(cachePath)) return; - + Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("alist.json"); + if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return; try (InputStream is = Files.newInputStream(cachePath)) { Map cache = GsonHelper.get().fromJson( new InputStreamReader(is), new TypeToken>(){}.getType() ); - this.cachedSha1 = cache.get("sha1"); - CraftEngine.instance().logger().info("[Alist] Loaded cached resource pack metadata"); } catch (Exception e) { CraftEngine.instance().logger().warn("[Alist] Failed to load cache " + cachePath, e); @@ -97,9 +94,9 @@ public class AlistHost implements ResourcePackHost { private void saveCacheToDisk() { Map cache = new HashMap<>(); cache.put("sha1", this.cachedSha1 != null ? this.cachedSha1 : ""); - - Path cachePath = CraftEngine.instance().dataFolderPath().resolve("alist.cache"); + Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("alist.json"); try { + Files.createDirectories(cachePath.getParent()); Files.writeString( cachePath, GsonHelper.get().toJson(cache), diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java index 98a1f483b..8f6cf2b92 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java @@ -49,18 +49,15 @@ public class DropboxHost implements ResourcePackHost { } public void readCacheFromDisk() { - Path cachePath = CraftEngine.instance().dataFolderPath().resolve("dropbox.cache"); + Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("dropbox.json"); if (!Files.exists(cachePath)) return; - try (InputStream is = Files.newInputStream(cachePath)) { JsonObject cache = GsonHelper.parseJsonToJsonObject(new String(is.readAllBytes(), StandardCharsets.UTF_8)); - this.url = getString(cache, "url"); this.sha1 = getString(cache, "sha1"); this.refreshToken = getString(cache, "refresh_token"); this.accessToken = getString(cache, "access_token"); this.expiresAt = getLong(cache, "expires_at"); - CraftEngine.instance().logger().info("[Dropbox] Loaded cached resource pack info"); } catch (Exception e) { CraftEngine.instance().logger().warn("[Dropbox] Failed to load cache " + cachePath, e); @@ -74,9 +71,9 @@ public class DropboxHost implements ResourcePackHost { cache.addProperty("refresh_token", this.refreshToken); cache.addProperty("access_token", this.accessToken); cache.addProperty("expires_at", this.expiresAt); - - Path cachePath = CraftEngine.instance().dataFolderPath().resolve("dropbox.cache"); + Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("dropbox.json"); try { + Files.createDirectories(cachePath); Files.writeString( cachePath, GsonHelper.get().toJson(cache), diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/GitLabHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/GitLabHost.java index c2d1cc5e9..b94adf1f1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/GitLabHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/GitLabHost.java @@ -45,23 +45,19 @@ public class GitLabHost implements ResourcePackHost { } public void readCacheFromDisk() { - Path cachePath = CraftEngine.instance().dataFolderPath().resolve("gitlab.cache"); - if (!Files.exists(cachePath)) return; - + Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("gitlab.json"); + if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return; try (InputStream is = Files.newInputStream(cachePath)) { Map cache = GsonHelper.get().fromJson( new InputStreamReader(is), new TypeToken>(){}.getType() ); - this.url = cache.get("url"); this.sha1 = cache.get("sha1"); - String uuidString = cache.get("uuid"); if (uuidString != null && !uuidString.isEmpty()) { this.uuid = UUID.fromString(uuidString); } - CraftEngine.instance().logger().info("[GitLab] Loaded cached resource pack info"); } catch (Exception e) { CraftEngine.instance().logger().warn( @@ -74,9 +70,9 @@ public class GitLabHost implements ResourcePackHost { cache.put("url", this.url); cache.put("sha1", this.sha1); cache.put("uuid", this.uuid != null ? this.uuid.toString() : ""); - - Path cachePath = CraftEngine.instance().dataFolderPath().resolve("gitlab.cache"); + Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("gitlab.json"); try { + Files.createDirectories(cachePath.getParent()); Files.writeString( cachePath, GsonHelper.get().toJson(cache), diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java index 36a965a8c..275521957 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java @@ -56,23 +56,19 @@ public class LobFileHost implements ResourcePackHost { } public void readCacheFromDisk() { - Path cachePath = CraftEngine.instance().dataFolderPath().resolve("lobfile.cache"); - if (!Files.exists(cachePath)) return; - + Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("lobfile.json"); + if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return; try (InputStream is = Files.newInputStream(cachePath)) { Map cache = GsonHelper.get().fromJson( new InputStreamReader(is), new TypeToken>(){}.getType() ); - this.url = cache.get("url"); this.sha1 = cache.get("sha1"); - String uuidString = cache.get("uuid"); if (uuidString != null && !uuidString.isEmpty()) { this.uuid = UUID.fromString(uuidString); } - CraftEngine.instance().logger().info("[LobFile] Loaded cached resource pack info"); } catch (Exception e) { CraftEngine.instance().logger().warn( @@ -85,9 +81,9 @@ public class LobFileHost implements ResourcePackHost { cache.put("url", this.url); cache.put("sha1", this.sha1); cache.put("uuid", this.uuid != null ? this.uuid.toString() : ""); - - Path cachePath = CraftEngine.instance().dataFolderPath().resolve("lobfile.cache"); + Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("lobfile.json"); try { + Files.createDirectories(cachePath.getParent()); Files.writeString( cachePath, GsonHelper.get().toJson(cache), diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java index 844e2f538..a15fa632f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java @@ -61,9 +61,8 @@ public class OneDriveHost implements ResourcePackHost { } public void readCacheFromDisk() { - Path cachePath = CraftEngine.instance().dataFolderPath().resolve("onedrive.cache"); - if (!Files.exists(cachePath)) return; - + Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("onedrive.json"); + if (!Files.exists(cachePath) || !Files.isRegularFile(cachePath)) return; try (InputStream is = Files.newInputStream(cachePath)) { Map cache = GsonHelper.get().fromJson( new InputStreamReader(is), @@ -91,9 +90,9 @@ public class OneDriveHost implements ResourcePackHost { cache.put("refresh-token-expires-in", String.valueOf(this.refreshToken.right().getTime())); cache.put("sha1", this.sha1); cache.put("file-id", this.fileId); - - Path cachePath = CraftEngine.instance().dataFolderPath().resolve("onedrive.cache"); + Path cachePath = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("onedrive.json"); try { + Files.createDirectories(cachePath.getParent()); Files.writeString( cachePath, GsonHelper.get().toJson(cache), diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/misc/Equipment.java b/core/src/main/java/net/momirealms/craftengine/core/pack/misc/Equipment.java deleted file mode 100644 index 0feb0f17e..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/misc/Equipment.java +++ /dev/null @@ -1,50 +0,0 @@ -package net.momirealms.craftengine.core.pack.misc; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import net.momirealms.craftengine.core.item.setting.ItemEquipment; - -import java.util.EnumMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; - -public class Equipment implements Supplier { - private final EnumMap> layers; - - public Equipment() { - this.layers = new EnumMap<>(EquipmentLayerType.class); - } - - public void addAll(ItemEquipment equipment) { - for (Map.Entry> entry : equipment.layers().entrySet()) { - List layers = entry.getValue(); - List previous = this.layers.put(entry.getKey(), layers); - if (previous != null && !previous.equals(layers)) { - // todo 是否异常 - } - } - } - - @Override - public JsonObject get() { - JsonObject jsonObject = new JsonObject(); - JsonObject layersJson = new JsonObject(); - jsonObject.add("layers", layersJson); - for (Map.Entry> entry : layers.entrySet()) { - EquipmentLayerType type = entry.getKey(); - List layerList = entry.getValue(); - setLayers(layersJson, layerList, type.id()); - } - return jsonObject; - } - - private void setLayers(JsonObject layersJson, List layers, String key) { - if (layers == null || layers.isEmpty()) return; - JsonArray layersArray = new JsonArray(); - for (ItemEquipment.Layer layer : layers) { - layersArray.add(layer.get()); - } - layersJson.add(key, layersArray); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/ItemModels.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/ItemModels.java index c4e5618c7..60eaeedb5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/ItemModels.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/ItemModels.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.pack.model; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -41,15 +40,13 @@ public class ItemModels { } public static void registerFactory(Key key, ItemModelFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.ITEM_MODEL_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.ITEM_MODEL_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.ITEM_MODEL_FACTORY) + .register(ResourceKey.create(Registries.ITEM_MODEL_FACTORY.location(), key), factory); } public static void registerReader(Key key, ItemModelReader reader) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.ITEM_MODEL_READER) - .registerForHolder(new ResourceKey<>(Registries.ITEM_MODEL_READER.location(), key)); - holder.bindValue(reader); + ((WritableRegistry) BuiltInRegistries.ITEM_MODEL_READER) + .register(ResourceKey.create(Registries.ITEM_MODEL_READER.location(), key), reader); } public static ItemModel fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/SelectItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/SelectItemModel.java index 8f449f423..f8c31c2b8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/SelectItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/SelectItemModel.java @@ -3,12 +3,12 @@ package net.momirealms.craftengine.core.pack.model; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.select.SelectProperties; import net.momirealms.craftengine.core.pack.model.select.SelectProperty; import net.momirealms.craftengine.core.pack.revision.Revision; 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.MinecraftVersion; import net.momirealms.craftengine.core.util.MiscUtils; @@ -25,11 +25,11 @@ public class SelectItemModel implements ItemModel { public static final Factory FACTORY = new Factory(); public static final Reader READER = new Reader(); private final SelectProperty property; - private final Map>, ItemModel> whenMap; + private final Map>, ItemModel> whenMap; private final ItemModel fallBack; public SelectItemModel(@NotNull SelectProperty property, - @NotNull Map>, ItemModel> whenMap, + @NotNull Map>, ItemModel> whenMap, @Nullable ItemModel fallBack) { this.property = property; this.whenMap = whenMap; @@ -40,7 +40,7 @@ public class SelectItemModel implements ItemModel { return this.property; } - public Map>, ItemModel> whenMap() { + public Map>, ItemModel> whenMap() { return this.whenMap; } @@ -55,17 +55,17 @@ public class SelectItemModel implements ItemModel { this.property.accept(json); JsonArray array = new JsonArray(); json.add("cases", array); - for (Map.Entry>, ItemModel> entry : this.whenMap.entrySet()) { + for (Map.Entry>, ItemModel> entry : this.whenMap.entrySet()) { JsonObject item = new JsonObject(); ItemModel itemModel = entry.getValue(); item.add("model", itemModel.apply(version)); - Either> either = entry.getKey(); + Either> either = entry.getKey(); if (either.primary().isPresent()) { - item.addProperty("when", either.primary().get()); + item.add("when", either.primary().get()); } else { - List list = either.fallback().get(); + List list = either.fallback().get(); JsonArray whens = new JsonArray(); - for (String e : list) { + for (JsonElement e : list) { whens.add(e); } item.add("when", whens); @@ -118,21 +118,21 @@ public class SelectItemModel implements ItemModel { if (casesObj instanceof List list) { List> cases = (List>) list; if (!cases.isEmpty()) { - Map>, ItemModel> whenMap = new HashMap<>(); + Map>, ItemModel> whenMap = new HashMap<>(); for (Map c : cases) { Object when = c.get("when"); if (when == null) { throw new LocalizedResourceConfigException("warning.config.item.model.select.case.missing_when"); } - Either> either; + Either> either; if (when instanceof List whenList) { - List whens = new ArrayList<>(whenList.size()); + List whens = new ArrayList<>(whenList.size()); for (Object o : whenList) { - whens.add(o.toString()); + whens.add(GsonHelper.get().toJsonTree(o)); } either = Either.ofFallback(whens); } else { - either = Either.ofPrimary(when.toString()); + either = Either.ofPrimary(GsonHelper.get().toJsonTree(when)); } Object model = c.get("model"); if (model == null) { @@ -158,22 +158,22 @@ public class SelectItemModel implements ItemModel { if (cases == null) { throw new IllegalArgumentException("cases is expected to be a JsonArray"); } - Map>, ItemModel> whenMap = new HashMap<>(cases.size()); + Map>, ItemModel> whenMap = new HashMap<>(cases.size()); for (JsonElement e : cases) { if (e instanceof JsonObject caseObj) { ItemModel model = ItemModels.fromJson(caseObj.getAsJsonObject("model")); JsonElement whenObj = caseObj.get("when"); - Either> either; + Either> either; if (whenObj instanceof JsonArray array) { - List whens = new ArrayList<>(array.size()); + List whens = new ArrayList<>(array.size()); for (JsonElement o : array) { - whens.add(o.getAsString()); + whens.add(o); } either = Either.ofFallback(whens); - } else if (whenObj instanceof JsonPrimitive primitive) { - either = Either.ofPrimary(primitive.getAsString()); + } else if (whenObj != null) { + either = Either.ofPrimary(whenObj); } else { - throw new IllegalArgumentException("when is expected to be either JsonPrimitive or JsonArray"); + throw new IllegalArgumentException("'when' should not be null"); } whenMap.put(either, model); } else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/ConditionProperties.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/ConditionProperties.java index 8c3c990b1..f2d5022fa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/ConditionProperties.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/condition/ConditionProperties.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.pack.model.condition; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -57,15 +56,13 @@ public class ConditionProperties { } public static void registerFactory(Key key, ConditionPropertyFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.CONDITION_PROPERTY_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.CONDITION_PROPERTY_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.CONDITION_PROPERTY_FACTORY) + .register(ResourceKey.create(Registries.CONDITION_PROPERTY_FACTORY.location(), key), factory); } public static void registerReader(Key key, ConditionPropertyReader reader) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.CONDITION_PROPERTY_READER) - .registerForHolder(new ResourceKey<>(Registries.CONDITION_PROPERTY_READER.location(), key)); - holder.bindValue(reader); + ((WritableRegistry) BuiltInRegistries.CONDITION_PROPERTY_READER) + .register(ResourceKey.create(Registries.CONDITION_PROPERTY_READER.location(), key), reader); } public static ConditionProperty fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/CrossBowPullingRangeDispatchProperty.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/CrossBowPullingRangeDispatchProperty.java index ab6acc9b4..e32a42e1f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/CrossBowPullingRangeDispatchProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/CrossBowPullingRangeDispatchProperty.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.util.Key; import java.util.Map; -public class CrossBowPullingRangeDispatchProperty implements RangeDispatchProperty, LegacyModelPredicate { +public class CrossBowPullingRangeDispatchProperty implements RangeDispatchProperty, LegacyModelPredicate { public static final Factory FACTORY = new Factory(); public static final Reader READER = new Reader(); public static final CrossBowPullingRangeDispatchProperty INSTANCE = new CrossBowPullingRangeDispatchProperty(); @@ -29,7 +29,7 @@ public class CrossBowPullingRangeDispatchProperty implements RangeDispatchProper } @Override - public Number toLegacyValue(Float value) { + public Number toLegacyValue(Number value) { return value; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/CustomModelDataRangeDispatchProperty.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/CustomModelDataRangeDispatchProperty.java index b31ac63f0..aeeb2dcc5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/CustomModelDataRangeDispatchProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/CustomModelDataRangeDispatchProperty.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; -public class CustomModelDataRangeDispatchProperty implements RangeDispatchProperty, LegacyModelPredicate { +public class CustomModelDataRangeDispatchProperty implements RangeDispatchProperty, LegacyModelPredicate { public static final Factory FACTORY = new Factory(); public static final Reader READER = new Reader(); private final int index; @@ -33,7 +33,7 @@ public class CustomModelDataRangeDispatchProperty implements RangeDispatchProper } @Override - public Number toLegacyValue(Float value) { + public Number toLegacyValue(Number value) { return value.intValue(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/DamageRangeDispatchProperty.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/DamageRangeDispatchProperty.java index 4ae98cfda..a37939865 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/DamageRangeDispatchProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/DamageRangeDispatchProperty.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; -public class DamageRangeDispatchProperty implements RangeDispatchProperty, LegacyModelPredicate { +public class DamageRangeDispatchProperty implements RangeDispatchProperty, LegacyModelPredicate { public static final Factory FACTORY = new Factory(); public static final Reader READER = new Reader(); private final boolean normalize; @@ -36,7 +36,7 @@ public class DamageRangeDispatchProperty implements RangeDispatchProperty, Legac } @Override - public Number toLegacyValue(Float value) { + public Number toLegacyValue(Number value) { if (this.normalize) return value; throw new RuntimeException("Enable 'normalize' option if you want to use 'damage' on 1.21.3 and below"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/RangeDispatchProperties.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/RangeDispatchProperties.java index 5b6033ce4..a8f09bcc0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/RangeDispatchProperties.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/RangeDispatchProperties.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.pack.model.rangedisptach; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -48,15 +47,13 @@ public class RangeDispatchProperties { } public static void registerFactory(Key key, RangeDispatchPropertyFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.RANGE_DISPATCH_PROPERTY_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.RANGE_DISPATCH_PROPERTY_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.RANGE_DISPATCH_PROPERTY_FACTORY) + .register(ResourceKey.create(Registries.RANGE_DISPATCH_PROPERTY_FACTORY.location(), key), factory); } public static void registerReader(Key key, RangeDispatchPropertyReader reader) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.RANGE_DISPATCH_PROPERTY_READER) - .registerForHolder(new ResourceKey<>(Registries.RANGE_DISPATCH_PROPERTY_READER.location(), key)); - holder.bindValue(reader); + ((WritableRegistry) BuiltInRegistries.RANGE_DISPATCH_PROPERTY_READER) + .register(ResourceKey.create(Registries.RANGE_DISPATCH_PROPERTY_READER.location(), key), reader); } public static RangeDispatchProperty fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/UseDurationRangeDispatchProperty.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/UseDurationRangeDispatchProperty.java index 65f8b8b53..a8f17ff84 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/UseDurationRangeDispatchProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/rangedisptach/UseDurationRangeDispatchProperty.java @@ -8,7 +8,7 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; -public class UseDurationRangeDispatchProperty implements RangeDispatchProperty, LegacyModelPredicate { +public class UseDurationRangeDispatchProperty implements RangeDispatchProperty, LegacyModelPredicate { public static final Factory FACTORY = new Factory(); public static final Reader READER = new Reader(); private final boolean remaining; @@ -37,7 +37,7 @@ public class UseDurationRangeDispatchProperty implements RangeDispatchProperty, } @Override - public Number toLegacyValue(Float value) { + public Number toLegacyValue(Number value) { return value; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/SelectProperties.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/SelectProperties.java index f1cd14106..3027db6ca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/SelectProperties.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/SelectProperties.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.pack.model.select; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -48,15 +47,13 @@ public class SelectProperties { } public static void registerFactory(Key key, SelectPropertyFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.SELECT_PROPERTY_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.SELECT_PROPERTY_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.SELECT_PROPERTY_FACTORY) + .register(ResourceKey.create(Registries.SELECT_PROPERTY_FACTORY.location(), key), factory); } public static void registerReader(Key key, SelectPropertyReader reader) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.SELECT_PROPERTY_READER) - .registerForHolder(new ResourceKey<>(Registries.SELECT_PROPERTY_READER.location(), key)); - holder.bindValue(reader); + ((WritableRegistry) BuiltInRegistries.SELECT_PROPERTY_READER) + .register(ResourceKey.create(Registries.SELECT_PROPERTY_READER.location(), key), reader); } public static SelectProperty fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/TrimMaterialSelectProperty.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/TrimMaterialSelectProperty.java index 434346bcd..6bdd5995f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/TrimMaterialSelectProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/select/TrimMaterialSelectProperty.java @@ -39,10 +39,7 @@ public class TrimMaterialSelectProperty implements SelectProperty, LegacyModelPr @Override public String legacyPredicateId(Key material) { - if (isArmor(material)) { - return "trim_type"; - } - return null; + return "trim_type"; } @Override @@ -54,11 +51,6 @@ public class TrimMaterialSelectProperty implements SelectProperty, LegacyModelPr return f; } - public boolean isArmor(Key material) { - String s = material.toString(); - return s.contains("helmet") || s.contains("chestplate") || s.contains("leggings") || s.contains("boots"); - } - public static class Factory implements SelectPropertyFactory { @Override public SelectProperty create(Map arguments) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/SpecialModels.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/SpecialModels.java index 16256d869..73f91a271 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/SpecialModels.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/special/SpecialModels.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.pack.model.special; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -54,15 +53,13 @@ public class SpecialModels { } public static void registerFactory(Key key, SpecialModelFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.SPECIAL_MODEL_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.SPECIAL_MODEL_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.SPECIAL_MODEL_FACTORY) + .register(ResourceKey.create(Registries.SPECIAL_MODEL_FACTORY.location(), key), factory); } - public static void registerReader(Key key, SpecialModelReader factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.SPECIAL_MODEL_READER) - .registerForHolder(new ResourceKey<>(Registries.SPECIAL_MODEL_READER.location(), key)); - holder.bindValue(factory); + public static void registerReader(Key key, SpecialModelReader reader) { + ((WritableRegistry) BuiltInRegistries.SPECIAL_MODEL_READER) + .register(ResourceKey.create(Registries.SPECIAL_MODEL_READER.location(), key), reader); } public static SpecialModel fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/Tints.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/Tints.java index 2aa81c197..d44d3102d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/Tints.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/tint/Tints.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.pack.model.tint; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -42,15 +41,13 @@ public class Tints { } public static void registerFactory(Key key, TintFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.TINT_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.TINT_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.TINT_FACTORY) + .register(ResourceKey.create(Registries.TINT_FACTORY.location(), key), factory); } public static void registerReader(Key key, TintReader reader) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.TINT_READER) - .registerForHolder(new ResourceKey<>(Registries.TINT_READER.location(), key)); - holder.bindValue(reader); + ((WritableRegistry) BuiltInRegistries.TINT_READER) + .register(ResourceKey.create(Registries.TINT_READER.location(), key), reader); } public static Tint fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/revision/Revisions.java b/core/src/main/java/net/momirealms/craftengine/core/pack/revision/Revisions.java index 82f434c2f..2b7fd7372 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/revision/Revisions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/revision/Revisions.java @@ -6,4 +6,5 @@ public final class Revisions { private Revisions() {} public static final Revision SINCE_1_21_6 = Revision.since(MinecraftVersions.V1_21_6); + public static final Revision SINCE_1_21_2 = Revision.since(MinecraftVersions.V1_21_2); } 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 04c267afc..ea29e3598 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 @@ -7,6 +7,9 @@ import net.momirealms.craftengine.core.entity.projectile.ProjectileManager; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.item.recipe.RecipeManager; +import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipeTypes; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplayTypes; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplayTypes; import net.momirealms.craftengine.core.loot.VanillaLootManager; import net.momirealms.craftengine.core.pack.PackManager; import net.momirealms.craftengine.core.plugin.classpath.ClassPathAppender; @@ -40,12 +43,10 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.Consumer; -import java.util.function.Supplier; public abstract class CraftEngine implements Plugin { private static CraftEngine instance; protected PluginLogger logger; - protected Consumer> debugger = (s) -> {}; protected Config config; protected Platform platform; protected ClassPathAppender classPathAppender; @@ -95,6 +96,9 @@ public abstract class CraftEngine implements Plugin { } protected void onPluginLoad() { + RecipeDisplayTypes.register(); + SlotDisplayTypes.register(); + LegacyRecipeTypes.register(); ((Logger) LogManager.getRootLogger()).addFilter(new LogFilter()); ((Logger) LogManager.getRootLogger()).addFilter(new DisconnectLogFilter()); } @@ -123,8 +127,6 @@ public abstract class CraftEngine implements Plugin { long time1 = System.currentTimeMillis(); // firstly reload main config this.config.load(); - // reset debugger - this.debugger = Config.debug() ? (s) -> logger.info("[Debug] " + s.get()) : (s) -> {}; // now we reload the translations this.translationManager.reload(); // clear the outdated cache by reloading the managers @@ -151,6 +153,8 @@ public abstract class CraftEngine implements Plugin { } catch (Exception e) { this.logger().warn("Failed to load resources folder", e); } + // register trims + this.itemManager.delayedLoad(); // init suggestions and packet mapper this.blockManager.delayedLoad(); // handle some special client lang for instance block_name @@ -263,7 +267,7 @@ public abstract class CraftEngine implements Plugin { // register font parser this.packManager.registerConfigSectionParsers(this.fontManager.parsers()); // register item parser - this.packManager.registerConfigSectionParser(this.itemManager.parser()); + this.packManager.registerConfigSectionParsers(this.itemManager.parsers()); // register furniture parser this.packManager.registerConfigSectionParser(this.furnitureManager.parser()); // register block parser @@ -340,11 +344,6 @@ public abstract class CraftEngine implements Plugin { return logger; } - @Override - public void debug(Supplier message) { - debugger.accept(message); - } - @Override public boolean isReloading() { return isReloading; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java index ea2888a6d..3521c3914 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Plugin.java @@ -28,7 +28,6 @@ import net.momirealms.craftengine.core.world.WorldManager; import java.io.File; import java.io.InputStream; import java.nio.file.Path; -import java.util.function.Supplier; public interface Plugin { @@ -90,8 +89,6 @@ public interface Plugin { VanillaLootManager vanillaLootManager(); - void debug(Supplier message); - CompatibilityManager compatibilityManager(); GlobalVariableManager globalVariableManager(); 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 72259e56d..425de32f9 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 @@ -13,6 +13,7 @@ import dev.dejvokep.boostedyaml.settings.updater.UpdaterSettings; import dev.dejvokep.boostedyaml.utils.format.NodeRole; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.entity.furniture.ColliderType; +import net.momirealms.craftengine.core.pack.AbstractPackManager; import net.momirealms.craftengine.core.pack.conflict.resolution.ResolutionConditional; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.PluginProperties; @@ -43,11 +44,16 @@ public class Config { private long size; protected boolean firstTime = true; - protected boolean debug; protected boolean checkUpdate; protected boolean metrics; protected boolean filterConfigurationPhaseDisconnect; + protected boolean debug$common; + protected boolean debug$packet; + protected boolean debug$item; + protected boolean debug$furniture; + protected boolean debug$resource_pack; + protected boolean resource_pack$remove_tinted_leaves_particle; protected boolean resource_pack$generate_mod_assets; protected boolean resource_pack$override_uniform_font; @@ -86,6 +92,7 @@ public class Config { protected String resource_pack$overlay_format; protected boolean resource_pack$delivery$kick_if_declined; + protected boolean resource_pack$delivery$kick_if_failed_to_apply; protected boolean resource_pack$delivery$send_on_join; protected boolean resource_pack$delivery$resend_on_upload; protected boolean resource_pack$delivery$auto_upload; @@ -122,8 +129,7 @@ public class Config { protected boolean recipe$enable; protected boolean recipe$disable_vanilla_recipes$all; protected Set recipe$disable_vanilla_recipes$list; - - protected boolean item$non_italic_tag; + protected List recipe$ingredient_sources; protected boolean image$illegal_characters_filter$command; protected boolean image$illegal_characters_filter$chat; @@ -144,6 +150,15 @@ public class Config { protected boolean image$intercept_packets$player_info; protected boolean image$intercept_packets$set_score; protected boolean image$intercept_packets$item; + protected boolean image$intercept_packets$advancement; + + protected boolean item$client_bound_model; + protected boolean item$non_italic_tag; + + protected String equipment$sacrificed_vanilla_armor$type; + protected Key equipment$sacrificed_vanilla_armor$asset_id; + protected Key equipment$sacrificed_vanilla_armor$humanoid; + protected Key equipment$sacrificed_vanilla_armor$humanoid_leggings; protected boolean emoji$chat; protected boolean emoji$book; @@ -223,12 +238,18 @@ public class Config { plugin.translationManager().forcedLocale(TranslationManager.parseLocale(config.getString("forced-locale", ""))); // basics - debug = config.getBoolean("debug", false); metrics = config.getBoolean("metrics", false); checkUpdate = config.getBoolean("update-checker", false); filterConfigurationPhaseDisconnect = config.getBoolean("filter-configuration-phase-disconnect", false); DisconnectLogFilter.instance().setEnable(filterConfigurationPhaseDisconnect); + // debug + debug$common = config.getBoolean("debug.common", false); + debug$packet = config.getBoolean("debug.packet", false); + debug$item = config.getBoolean("debug.item", false); + debug$furniture = config.getBoolean("debug.furniture", false); + debug$resource_pack = config.getBoolean("debug.resource-pack", false); + // resource pack resource_pack$override_uniform_font = config.getBoolean("resource-pack.override-uniform-font", false); resource_pack$generate_mod_assets = config.getBoolean("resource-pack.generate-mod-assets", false); @@ -241,6 +262,7 @@ public class Config { resource_pack$delivery$send_on_join = config.getBoolean("resource-pack.delivery.send-on-join", true); resource_pack$delivery$resend_on_upload = config.getBoolean("resource-pack.delivery.resend-on-upload", true); resource_pack$delivery$kick_if_declined = config.getBoolean("resource-pack.delivery.kick-if-declined", true); + resource_pack$delivery$kick_if_failed_to_apply = config.getBoolean("resource-pack.delivery.kick-if-failed-to-apply", true); resource_pack$delivery$auto_upload = config.getBoolean("resource-pack.delivery.auto-upload", true); resource_pack$delivery$file_to_upload = resolvePath(config.getString("resource-pack.delivery.file-to-upload", "./generated/resource_pack.zip")); resource_pack$send$prompt = AdventureHelper.miniMessage().deserialize(config.getString("resource-pack.delivery.prompt", "To fully experience our server, please accept our custom resource pack.")); @@ -284,9 +306,6 @@ public class Config { resource_pack$duplicated_files_handler = List.of(); } - // item - item$non_italic_tag = config.getBoolean("item.non-italic-tag", false); - // performance 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); @@ -326,6 +345,21 @@ public class Config { furniture$hide_base_entity = config.getBoolean("furniture.hide-base-entity", true); furniture$collision_entity_type = ColliderType.valueOf(config.getString("furniture.collision-entity-type", "interaction").toUpperCase(Locale.ENGLISH)); + // equipment + equipment$sacrificed_vanilla_armor$type = config.getString("equipment.sacrificed-vanilla-armor.type", "chainmail").toLowerCase(Locale.ENGLISH); + if (!AbstractPackManager.ALLOWED_VANILLA_EQUIPMENT.contains(equipment$sacrificed_vanilla_armor$type)) { + TranslationManager.instance().log("warning.config.equipment.invalid_sacrificed_armor", equipment$sacrificed_vanilla_armor$type); + equipment$sacrificed_vanilla_armor$type = "chainmail"; + } + + equipment$sacrificed_vanilla_armor$asset_id = Key.of(config.getString("equipment.sacrificed-vanilla-armor.asset-id", "minecraft:chainmail")); + equipment$sacrificed_vanilla_armor$humanoid = Key.of(config.getString("equipment.sacrificed-vanilla-armor.humanoid", "minecraft:trims/entity/humanoid/chainmail")); + equipment$sacrificed_vanilla_armor$humanoid_leggings = Key.of(config.getString("equipment.sacrificed-vanilla-armor.humanoid-leggings", "minecraft:trims/entity/humanoid_leggings/chainmail")); + + // item + item$client_bound_model = config.getBoolean("item.client-bound-model", false); + item$non_italic_tag = config.getBoolean("item.non-italic-tag", false); + // block block$sound_system$enable = config.getBoolean("block.sound-system.enable", true); block$simplify_adventure_break_check = config.getBoolean("block.simplify-adventure-break-check", false); @@ -338,6 +372,7 @@ public class Config { recipe$enable = config.getBoolean("recipe.enable", true); recipe$disable_vanilla_recipes$all = config.getBoolean("recipe.disable-vanilla-recipes.all", false); recipe$disable_vanilla_recipes$list = config.getStringList("recipe.disable-vanilla-recipes.list").stream().map(Key::of).collect(Collectors.toSet()); + recipe$ingredient_sources = config.getStringList("recipe.ingredient-sources"); // image image$illegal_characters_filter$anvil = config.getBoolean("image.illegal-characters-filter.anvil", true); @@ -359,6 +394,7 @@ public class Config { image$intercept_packets$player_info = config.getBoolean("image.intercept-packets.player-info", true); image$intercept_packets$set_score = config.getBoolean("image.intercept-packets.set-score", true); image$intercept_packets$item = config.getBoolean("image.intercept-packets.item", true); + image$intercept_packets$advancement = config.getBoolean("image.intercept-packets.advancement", true); // emoji emoji$chat = config.getBoolean("emoji.chat", true); @@ -380,8 +416,24 @@ public class Config { return instance.configVersion; } - public static boolean debug() { - return instance.debug; + public static boolean debugCommon() { + return instance.debug$common; + } + + public static boolean debugPacket() { + return instance.debug$packet; + } + + public static boolean debugItem() { + return instance.debug$item; + } + + public static boolean debugFurniture() { + return instance.debug$furniture; + } + + public static boolean debugResourcePack() { + return instance.debug$resource_pack; } public static boolean checkUpdate() { @@ -456,10 +508,6 @@ public class Config { return instance.recipe$disable_vanilla_recipes$list; } - public static boolean nonItalic() { - return instance.item$non_italic_tag; - } - public static boolean restoreVanillaBlocks() { return instance.chunk_system$restore_vanilla_blocks_on_chunk_unload && instance.chunk_system$restore_custom_blocks_on_chunk_load; } @@ -488,6 +536,10 @@ public class Config { return instance.resource_pack$delivery$kick_if_declined; } + public static boolean kickOnFailedApply() { + return instance.resource_pack$delivery$kick_if_failed_to_apply; + } + public static Component resourcePackPrompt() { return instance.resource_pack$send$prompt; } @@ -692,6 +744,10 @@ public class Config { return instance.image$intercept_packets$item; } + public static boolean interceptAdvancement() { + return instance.image$intercept_packets$advancement; + } + public static boolean predictBreaking() { return instance.block$predict_breaking; } @@ -728,6 +784,10 @@ public class Config { return instance.chunk_system$cache_system; } + public static boolean addNonItalicTag() { + return instance.item$non_italic_tag; + } + public static boolean fastInjection() { return instance.chunk_system$injection$use_fast_method; } @@ -748,6 +808,30 @@ public class Config { return instance.resource_pack$overlay_format.replace("{version}", version); } + public static Key sacrificedAssetId() { + return instance.equipment$sacrificed_vanilla_armor$asset_id; + } + + public static Key sacrificedHumanoid() { + return instance.equipment$sacrificed_vanilla_armor$humanoid; + } + + public static Key sacrificedHumanoidLeggings() { + return instance.equipment$sacrificed_vanilla_armor$humanoid_leggings; + } + + public static String sacrificedVanillaArmorType() { + return instance.equipment$sacrificed_vanilla_armor$type; + } + + public static boolean globalClientboundModel() { + return instance.item$client_bound_model; + } + + public static List recipeIngredientSources() { + return instance.recipe$ingredient_sources; + } + public YamlDocument loadOrCreateYamlData(String fileName) { Path path = this.plugin.dataFolderPath().resolve(fileName); if (!Files.exists(path)) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigParser.java index 4d6fae451..901fbe8a9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigParser.java @@ -29,4 +29,10 @@ public interface ConfigParser extends Comparable { default int compareTo(@NotNull ConfigParser another) { return Integer.compare(loadingSequence(), another.loadingSequence()); } + + default void postProcess() { + } + + default void preProcess() { + } } 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 127c2220c..568679a97 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 @@ -118,7 +118,7 @@ public class StringKeyConstructor extends SafeConstructor { // 如果路径中存在一个非map的值, 这意味着 // 当存在了 {aa: bb}, 又想要写入 {aa::bb::c: value} 时, 会触发这个警告, 然后会覆盖之前的. - if (existingValue != null) logWarning("key_path_conflict", keyPart, keyNode); + if (existingValue != null) logWarning("inconsistent_value_type", keyPart, keyNode); // 创建层级 Map newMap = new LinkedHashMap<>(); 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 b920c0d68..82fd38d45 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 @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.plugin.config.template; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -19,9 +18,8 @@ public class TemplateArguments { public static final Key OBJECT = Key.of("craftengine:object"); // No Factory, internal use public static void register(Key key, TemplateArgumentFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.TEMPLATE_ARGUMENT_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.TEMPLATE_ARGUMENT_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.TEMPLATE_ARGUMENT_FACTORY) + .register(ResourceKey.create(Registries.TEMPLATE_ARGUMENT_FACTORY.location(), key), factory); } static { 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 55fba96cb..86840c238 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 @@ -65,6 +65,7 @@ public interface TemplateManager extends Manageable { private final String placeholder; private final String rawText; private final Object defaultValue; + private final boolean hasDefaultValue; public Placeholder(String placeholderContent) { this.rawText = "${" + placeholderContent + "}"; @@ -72,16 +73,17 @@ public interface TemplateManager extends Manageable { if (separatorIndex == -1) { this.placeholder = placeholderContent; this.defaultValue = null; + this.hasDefaultValue = false; } else { this.placeholder = placeholderContent.substring(0, separatorIndex); String defaultValueString = placeholderContent.substring(separatorIndex + 2); try { - // TODO 改进报错检测 this.defaultValue = new SNBTReader(defaultValueString).deserializeAsJava(); } catch (LocalizedResourceConfigException e) { e.appendTailArgument(this.placeholder); throw e; } + this.hasDefaultValue = true; } } @@ -95,7 +97,10 @@ public interface TemplateManager extends Manageable { if (replacement != null) { return replacement.get(arguments); } - return this.defaultValue; + if (this.hasDefaultValue) { + return this.defaultValue; + } + throw new LocalizedResourceConfigException("warning.config.template.argument.missing_value", this.rawText); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java index a27774af1..05bb914e9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/EnchantmentCondition.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.plugin.context.condition; -import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java index a53ebe386..20c6fd81a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/TableBonusCondition.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.plugin.context.condition; -import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java index 5e6a110fa..e5fc50979 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.condition.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -40,9 +39,8 @@ public class EventConditions { } public static void register(Key key, ConditionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.EVENT_CONDITION_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.EVENT_CONDITION_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry>) BuiltInRegistries.EVENT_CONDITION_FACTORY) + .register(ResourceKey.create(Registries.EVENT_CONDITION_FACTORY.location(), key), factory); } public static Condition fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index 8613eb5c4..1541a39d2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -42,9 +41,8 @@ public class EventFunctions { } public static void register(Key key, FunctionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.EVENT_FUNCTION_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.EVENT_FUNCTION_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry>) BuiltInRegistries.EVENT_FUNCTION_FACTORY) + .register(ResourceKey.create(Registries.EVENT_FUNCTION_FACTORY.location(), key), factory); } public static Function fromMap(Map map) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java index d7c039825..bc65826b4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ParticleFunction.java @@ -1,7 +1,8 @@ package net.momirealms.craftengine.core.plugin.context.function; -import net.momirealms.craftengine.core.block.LazyBlockState; -import net.momirealms.craftengine.core.item.DelayedInitItem; +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; @@ -9,6 +10,7 @@ import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Color; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.LazyReference; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.Position; import net.momirealms.craftengine.core.world.Vec3d; @@ -20,13 +22,20 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Supplier; public class ParticleFunction extends AbstractConditionalFunction { public static final Map, ParticleData>> DATA_TYPES = new HashMap<>(); static { registerParticleData(map -> new BlockStateData( - new LazyBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("block-state"), "warning.config.function.particle.missing_block_state"))), + LazyReference.lazyReference(new Supplier<>() { + final String blockState = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("block-state"), "warning.config.function.particle.missing_block_state"); + @Override + public BlockStateWrapper get() { + return CraftEngine.instance().blockManager().createPackedBlockState(this.blockState); + } + })), ParticleTypes.BLOCK, ParticleTypes.FALLING_DUST, ParticleTypes.DUST_PILLAR, ParticleTypes.BLOCK_CRUMBLE, ParticleTypes.BLOCK_MARKER); registerParticleData(map -> new ColorData( Color.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("color"), "warning.config.function.particle.missing_color").split(","))), @@ -47,7 +56,14 @@ public class ParticleFunction extends AbstractConditionalFu ResourceConfigUtils.getAsFloat(map.getOrDefault("scale", 1), "scale")), ParticleTypes.DUST_COLOR_TRANSITION); registerParticleData(map -> new ItemStackData( - new DelayedInitItem(Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("item"), "warning.config.function.particle.missing_item")))), + LazyReference.lazyReference(new Supplier<>() { + final Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("item"), "warning.config.function.particle.missing_item")); + @Override + public Item get() { + return CraftEngine.instance().itemManager().createWrappedItem(this.itemId, null); + } + }) + ), ParticleTypes.ITEM); registerParticleData(map -> new VibrationData( NumberProviders.fromObject(map.getOrDefault("target-x", 0)), diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java index 892bb83e3..2efaf8877 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java @@ -1,13 +1,15 @@ package net.momirealms.craftengine.core.plugin.context.function; -import net.momirealms.craftengine.core.block.LazyBlockState; +import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.UpdateOption; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.LazyReference; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.World; @@ -18,13 +20,13 @@ import java.util.Map; import java.util.Optional; public class PlaceBlockFunction extends AbstractConditionalFunction { - private final LazyBlockState lazyBlockState; + private final LazyReference lazyBlockState; private final NumberProvider x; private final NumberProvider y; private final NumberProvider z; private final NumberProvider updateFlags; - public PlaceBlockFunction(LazyBlockState lazyBlockState, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider updateFlags, List> predicates) { + public PlaceBlockFunction(LazyReference lazyBlockState, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider updateFlags, List> predicates) { super(predicates); this.lazyBlockState = lazyBlockState; this.x = x; @@ -38,7 +40,7 @@ public class PlaceBlockFunction extends AbstractConditional Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); if (optionalWorldPosition.isPresent()) { World world = optionalWorldPosition.get().world(); - world.setBlockAt(MCUtils.fastFloor(this.x.getDouble(ctx)), MCUtils.fastFloor(this.y.getDouble(ctx)), MCUtils.fastFloor(this.z.getDouble(ctx)), this.lazyBlockState.getState(), this.updateFlags.getInt(ctx)); + world.setBlockAt(MCUtils.fastFloor(this.x.getDouble(ctx)), MCUtils.fastFloor(this.y.getDouble(ctx)), MCUtils.fastFloor(this.z.getDouble(ctx)), this.lazyBlockState.get(), this.updateFlags.getInt(ctx)); } } @@ -56,12 +58,11 @@ public class PlaceBlockFunction extends AbstractConditional @Override public Function create(Map arguments) { String state = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("block-state"), "warning.config.function.place_block.missing_block_state"); - LazyBlockState lazyBlockState = new LazyBlockState(state); NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); NumberProvider flags = Optional.ofNullable(arguments.get("update-flags")).map(NumberProviders::fromObject).orElse(NumberProviders.direct(UpdateOption.UPDATE_ALL.flags())); - return new PlaceBlockFunction<>(lazyBlockState, x, y, z, flags, getPredicates(arguments)); + return new PlaceBlockFunction<>(LazyReference.lazyReference(() -> CraftEngine.instance().blockManager().createPackedBlockState(state)), x, y, z, flags, getPredicates(arguments)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaySoundFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaySoundFunction.java index ea5f4c547..00004bbb8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaySoundFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaySoundFunction.java @@ -1,10 +1,13 @@ package net.momirealms.craftengine.core.plugin.context.function; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -25,8 +28,19 @@ public class PlaySoundFunction extends AbstractConditionalF private final NumberProvider volume; private final NumberProvider pitch; private final SoundSource source; + private final PlayerSelector selector; - public PlaySoundFunction(Key soundEvent, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider volume, NumberProvider pitch, SoundSource source, List> predicates) { + public PlaySoundFunction( + Key soundEvent, + NumberProvider x, + NumberProvider y, + NumberProvider z, + NumberProvider volume, + NumberProvider pitch, + SoundSource source, + PlayerSelector selector, + List> predicates + ) { super(predicates); this.soundEvent = soundEvent; this.x = x; @@ -35,15 +49,22 @@ public class PlaySoundFunction extends AbstractConditionalF this.volume = volume; this.pitch = pitch; this.source = source; + this.selector = selector; } @Override public void runInternal(CTX ctx) { - Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); - if (optionalWorldPosition.isPresent()) { - World world = optionalWorldPosition.get().world(); - world.playSound(new Vec3d(this.x.getDouble(ctx), this.y.getDouble(ctx), this.z.getDouble(ctx)), - this.soundEvent, this.volume.getFloat(ctx), this.pitch.getFloat(ctx), this.source); + if (this.selector == null) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isPresent()) { + World world = optionalWorldPosition.get().world(); + world.playSound(new Vec3d(this.x.getDouble(ctx), this.y.getDouble(ctx), this.z.getDouble(ctx)), + this.soundEvent, this.volume.getFloat(ctx), this.pitch.getFloat(ctx), this.source); + } + } else { + for (Player player : selector.get(ctx)) { + player.playSound(this.soundEvent, this.source, this.volume.getFloat(ctx), this.pitch.getFloat(ctx)); + } } } @@ -67,7 +88,8 @@ public class PlaySoundFunction extends AbstractConditionalF NumberProvider volume = NumberProviders.fromObject(arguments.getOrDefault("volume", 1)); NumberProvider pitch = NumberProviders.fromObject(arguments.getOrDefault("pitch", 1)); SoundSource source = Optional.ofNullable(arguments.get("source")).map(String::valueOf).map(it -> SoundSource.valueOf(it.toUpperCase(Locale.ENGLISH))).orElse(SoundSource.MASTER); - return new PlaySoundFunction<>(soundEvent, x, y, z, volume, pitch, source, getPredicates(arguments)); + PlayerSelector selector = PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()); + return new PlaySoundFunction<>(soundEvent, x, y, z, volume, pitch, source, selector, getPredicates(arguments)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java index 2d7fb1591..22b698c86 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.plugin.context.number; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -27,9 +26,8 @@ public class NumberProviders { } public static void register(Key key, NumberProviderFactory factory) { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.NUMBER_PROVIDER_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.NUMBER_PROVIDER_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry) BuiltInRegistries.NUMBER_PROVIDER_FACTORY) + .register(ResourceKey.create(Registries.NUMBER_PROVIDER_FACTORY.location(), key), factory); } public static List fromMapList(List> mapList) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java index c1198e8d9..ab5d4a7ca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/PlayerSelectors.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; @@ -26,9 +25,8 @@ public class PlayerSelectors { } public static void register(Key key, PlayerSelectorFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_SELECTOR_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.PLAYER_SELECTOR_FACTORY.location(), key)); - holder.bindValue(factory); + ((WritableRegistry>) BuiltInRegistries.PLAYER_SELECTOR_FACTORY) + .register(ResourceKey.create(Registries.PLAYER_SELECTOR_FACTORY.location(), key), factory); } @Nullable diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index 88a341729..499b9bc3c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -16,11 +16,7 @@ import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.gui.*; import net.momirealms.craftengine.core.plugin.gui.Ingredient; -import net.momirealms.craftengine.core.registry.Holder; -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.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.*; import java.nio.file.Path; import java.util.*; @@ -161,7 +157,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { List iconList = this.categoryOnMainPage.stream().map(it -> { Item item = this.plugin.itemManager().createWrappedItem(it.icon(), player); - if (item == null) { + if (ItemUtils.isEmpty(item)) { this.plugin.logger().warn("Can't not find item " + it.icon() + " for category icon"); return null; } @@ -246,7 +242,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { Category subCategory = this.byId.get(Key.of(subCategoryId)); if (subCategory == null) return null; Item item = this.plugin.itemManager().createWrappedItem(subCategory.icon(), player); - if (item == null) { + if (ItemUtils.isEmpty(item)) { if (!subCategory.icon().equals(ItemKeys.AIR)) { item = this.plugin.itemManager().createWrappedItem(ItemKeys.BARRIER, player); item.customNameJson(AdventureHelper.componentToJson(AdventureHelper.miniMessage().deserialize(subCategory.displayName(), ItemBuildContext.EMPTY.tagResolvers()))); @@ -265,7 +261,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { Key itemId = Key.of(it); Item item = this.plugin.itemManager().createWrappedItem(itemId, player); boolean canGoFurther; - if (item == null) { + if (ItemUtils.isEmpty(item)) { if (!itemId.equals(ItemKeys.AIR)) { item = this.plugin.itemManager().createWrappedItem(ItemKeys.BARRIER, player); item.customNameJson(AdventureHelper.componentToJson(Component.text(it).decoration(TextDecoration.ITALIC, TextDecoration.State.FALSE).color(NamedTextColor.RED))); @@ -503,11 +499,10 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } })); - List> templates = new ArrayList<>(); Optional.ofNullable(recipe.template()).ifPresent(it -> { - for (Holder in : it.items()) { - templates.add(this.plugin.itemManager().createWrappedItem(in.value(), player)); + for (UniqueKey in : it.items()) { + templates.add(this.plugin.itemManager().createWrappedItem(in.key(), player)); } }); layout.addIngredient('A', templates.isEmpty() ? GuiElement.EMPTY : GuiElement.recipeIngredient(templates, (e, c) -> { @@ -539,8 +534,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { List> bases = new ArrayList<>(); Optional.ofNullable(recipe.base()).ifPresent(it -> { - for (Holder in : it.items()) { - bases.add(this.plugin.itemManager().createWrappedItem(in.value(), player)); + for (UniqueKey in : it.items()) { + bases.add(this.plugin.itemManager().createWrappedItem(in.key(), player)); } }); layout.addIngredient('B', bases.isEmpty() ? GuiElement.EMPTY : GuiElement.recipeIngredient(bases, (e, c) -> { @@ -572,8 +567,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { List> additions = new ArrayList<>(); Optional.ofNullable(recipe.addition()).ifPresent(it -> { - for (Holder in : it.items()) { - additions.add(this.plugin.itemManager().createWrappedItem(in.value(), player)); + for (UniqueKey in : it.items()) { + additions.add(this.plugin.itemManager().createWrappedItem(in.key(), player)); } }); layout.addIngredient('C', additions.isEmpty() ? GuiElement.EMPTY : GuiElement.recipeIngredient(additions, (e, c) -> { @@ -623,8 +618,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { List> ingredients = new ArrayList<>(); net.momirealms.craftengine.core.item.recipe.Ingredient ingredient = recipe.ingredient(); - for (Holder in : ingredient.items()) { - ingredients.add(this.plugin.itemManager().createWrappedItem(in.value(), player)); + for (UniqueKey in : ingredient.items()) { + ingredients.add(this.plugin.itemManager().createWrappedItem(in.key(), player)); } GuiLayout layout = new GuiLayout( " ", @@ -756,8 +751,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { List> ingredients = new ArrayList<>(); net.momirealms.craftengine.core.item.recipe.Ingredient ingredient = recipe.ingredient(); - for (Holder in : ingredient.items()) { - ingredients.add(this.plugin.itemManager().createWrappedItem(in.value(), player)); + for (UniqueKey in : ingredient.items()) { + ingredients.add(this.plugin.itemManager().createWrappedItem(in.key(), player)); } GuiLayout layout = new GuiLayout( " ", @@ -1001,8 +996,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { layout.addIngredient(currentChar, Ingredient.EMPTY); } else { List> ingredients = new ArrayList<>(); - for (Holder in : ingredient.items()) { - ingredients.add(this.plugin.itemManager().createWrappedItem(in.value(), player)); + for (UniqueKey in : ingredient.items()) { + ingredients.add(this.plugin.itemManager().createWrappedItem(in.key(), player)); } layout.addIngredient(currentChar, GuiElement.recipeIngredient(ingredients, (e, c) -> { c.cancel(); @@ -1044,8 +1039,8 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { char currentChar = (char) (start + x + y * 3); if (i < ingredients.size()) { List> ingredientItems = new ArrayList<>(); - for (Holder in : ingredients.get(i).items()) { - ingredientItems.add(this.plugin.itemManager().createWrappedItem(in.value(), player)); + for (UniqueKey in : ingredients.get(i).items()) { + ingredientItems.add(this.plugin.itemManager().createWrappedItem(in.key(), player)); } layout.addIngredient(currentChar, GuiElement.recipeIngredient(ingredientItems, (e, c) -> { c.cancel(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/logger/Debugger.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/logger/Debugger.java new file mode 100644 index 000000000..4ca696c84 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/logger/Debugger.java @@ -0,0 +1,32 @@ +package net.momirealms.craftengine.core.plugin.logger; + +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; + +import java.util.function.Supplier; + +public enum Debugger { + COMMON(Config::debugCommon), + PACKET(Config::debugPacket), + FURNITURE(Config::debugFurniture), + RESOURCE_PACK(Config::debugFurniture), + ITEM(Config::debugItem); + + private final Supplier condition; + + Debugger(Supplier condition) { + this.condition = condition; + } + + public void debug(Supplier message) { + if (this.condition.get()) { + CraftEngine.instance().logger().info("[DEBUG] " + message.get()); + } + } + + public void warn(Supplier message, Throwable e) { + if (this.condition.get()) { + CraftEngine.instance().logger().warn("[DEBUG] " + message.get(), e); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java index 2dc4f282a..9ff316fcf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetWorkUser.java @@ -57,11 +57,9 @@ public interface NetWorkUser { void addResourcePackUUID(UUID uuid); - ProtocolVersion protocolVersion(); + boolean isResourcePackLoading(UUID uuid); - void setProtocolVersion(int protocolVersion); + void setShouldProcessFinishConfiguration(boolean shouldProcess); - boolean sentResourcePack(); - - void setSentResourcePack(boolean sentResourcePack); + boolean shouldProcessFinishConfiguration(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java index 79e04f318..fc2d707ec 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/ProtocolVersion.java @@ -15,7 +15,8 @@ public enum ProtocolVersion { V1_21_3(768, "1.21.3"), V1_21_4(769, "1.21.4"), V1_21_5(770, "1.21.5"), - V1_21_6(771, "1.21.6"); + V1_21_6(771, "1.21.6"), + V1_21_7(772, "1.21.7"); private final int id; private final String name; diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/MappedRegistry.java b/core/src/main/java/net/momirealms/craftengine/core/registry/AbstractMappedRegistry.java similarity index 53% rename from core/src/main/java/net/momirealms/craftengine/core/registry/MappedRegistry.java rename to core/src/main/java/net/momirealms/craftengine/core/registry/AbstractMappedRegistry.java index 219c1d5b7..efefaa5ba 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/MappedRegistry.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/AbstractMappedRegistry.java @@ -7,12 +7,13 @@ import org.jetbrains.annotations.Nullable; import java.util.*; -public class MappedRegistry implements WritableRegistry { - private final ResourceKey> key; - private final Map> byId = new HashMap<>(2048); - private final Map, Holder.Reference> byResourceKey = new HashMap<>(2048); +public abstract class AbstractMappedRegistry implements WritableRegistry { + protected final ResourceKey> key; + protected final Map> byResourceLocation = new HashMap<>(512); + protected final Map, Holder.Reference> byResourceKey = new HashMap<>(512); + protected final List> byId = new ArrayList<>(512); - public MappedRegistry(ResourceKey> key) { + protected AbstractMappedRegistry(ResourceKey> key) { this.key = key; } @@ -21,29 +22,6 @@ public class MappedRegistry implements WritableRegistry { return this.key; } - @Override - public Holder.Reference registerForHolder(ResourceKey key) { - Objects.requireNonNull(key); - if (!key.registry().equals(this.key.location())) { - throw new IllegalStateException(key + " is not allowed to be registered in " + this.key); - } - if (this.byId.containsKey(key.location())) { - throw new IllegalStateException("Adding duplicate key '" + key + "' to registry"); - } else { - Holder.Reference reference = this.byResourceKey.computeIfAbsent(key, k -> Holder.Reference.create(this, k)); - this.byResourceKey.put(key, reference); - this.byId.put(key.location(), reference); - return reference; - } - } - - @Override - public Holder.Reference register(ResourceKey key, T value) { - Holder.Reference holder = registerForHolder(key); - holder.bindValue(value); - return holder; - } - @Nullable @Override public T getValue(@Nullable ResourceKey key) { @@ -52,7 +30,7 @@ public class MappedRegistry implements WritableRegistry { @Override public Optional> get(Key id) { - return Optional.ofNullable(this.byId.get(id)); + return Optional.ofNullable(this.byResourceLocation.get(id)); } @Override @@ -63,10 +41,16 @@ public class MappedRegistry implements WritableRegistry { @Nullable @Override public T getValue(@Nullable Key id) { - Holder.Reference reference = this.byId.get(id); + Holder.Reference reference = this.byResourceLocation.get(id); return getValueFromNullable(reference); } + @Override + public @Nullable T getValue(int id) { + if (id < 0 || id >= this.byId.size()) return null; + return getValueFromNullable(this.byId.get(id)); + } + @Nullable private static T getValueFromNullable(@Nullable Holder.Reference entry) { return entry != null ? entry.value() : null; @@ -74,7 +58,7 @@ public class MappedRegistry implements WritableRegistry { @Override public Set keySet() { - return Collections.unmodifiableSet(this.byId.keySet()); + return Collections.unmodifiableSet(this.byResourceLocation.keySet()); } @Override @@ -84,7 +68,7 @@ public class MappedRegistry implements WritableRegistry { @Override public boolean containsKey(Key id) { - return this.byId.containsKey(id); + return this.byResourceLocation.containsKey(id); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 46c6061b6..0314031ad 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -5,8 +5,12 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.PropertyFactory; import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.RecipeFactory; +import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipe; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.loot.entry.LootEntryContainerFactory; import net.momirealms.craftengine.core.loot.function.ApplyBonusCountFunction; @@ -32,44 +36,50 @@ import net.momirealms.craftengine.core.plugin.context.condition.ConditionFactory import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; import net.momirealms.craftengine.core.plugin.context.number.NumberProviderFactory; import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectorFactory; -import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; public class BuiltInRegistries { - public static final Registry BLOCK = createRegistry(Registries.BLOCK); - public static final Registry OPTIMIZED_ITEM_ID = createRegistry(Registries.OPTIMIZED_ITEM_ID); - public static final Registry BLOCK_BEHAVIOR_FACTORY = createRegistry(Registries.BLOCK_BEHAVIOR_FACTORY); - public static final Registry ITEM_BEHAVIOR_FACTORY = createRegistry(Registries.ITEM_BEHAVIOR_FACTORY); - public static final Registry PROPERTY_FACTORY = createRegistry(Registries.PROPERTY_FACTORY); - public static final Registry> LOOT_FUNCTION_FACTORY = createRegistry(Registries.LOOT_FUNCTION_FACTORY); - public static final Registry> LOOT_CONDITION_FACTORY = createRegistry(Registries.LOOT_CONDITION_FACTORY); - public static final Registry> LOOT_ENTRY_CONTAINER_FACTORY = createRegistry(Registries.LOOT_ENTRY_CONTAINER_FACTORY); - public static final Registry NUMBER_PROVIDER_FACTORY = createRegistry(Registries.NUMBER_PROVIDER_FACTORY); - public static final Registry TEMPLATE_ARGUMENT_FACTORY = createRegistry(Registries.TEMPLATE_ARGUMENT_FACTORY); - public static final Registry ITEM_MODEL_FACTORY = createRegistry(Registries.ITEM_MODEL_FACTORY); - public static final Registry ITEM_MODEL_READER = createRegistry(Registries.ITEM_MODEL_READER); - public static final Registry TINT_FACTORY = createRegistry(Registries.TINT_FACTORY); - public static final Registry TINT_READER = createRegistry(Registries.TINT_READER); - public static final Registry SPECIAL_MODEL_FACTORY = createRegistry(Registries.SPECIAL_MODEL_FACTORY); - public static final Registry SPECIAL_MODEL_READER = createRegistry(Registries.SPECIAL_MODEL_READER); - public static final Registry RANGE_DISPATCH_PROPERTY_FACTORY = createRegistry(Registries.RANGE_DISPATCH_PROPERTY_FACTORY); - public static final Registry RANGE_DISPATCH_PROPERTY_READER = createRegistry(Registries.RANGE_DISPATCH_PROPERTY_READER); - public static final Registry CONDITION_PROPERTY_FACTORY = createRegistry(Registries.CONDITION_PROPERTY_FACTORY); - public static final Registry CONDITION_PROPERTY_READER = createRegistry(Registries.CONDITION_PROPERTY_READER); - public static final Registry SELECT_PROPERTY_FACTORY = createRegistry(Registries.SELECT_PROPERTY_FACTORY); - public static final Registry SELECT_PROPERTY_READER = createRegistry(Registries.SELECT_PROPERTY_READER); - public static final Registry> RECIPE_FACTORY = createRegistry(Registries.RECIPE_FACTORY); - public static final Registry FORMULA_FACTORY = createRegistry(Registries.FORMULA_FACTORY); - public static final Registry> PATH_MATCHER_FACTORY = createRegistry(Registries.PATH_MATCHER_FACTORY); - public static final Registry RESOLUTION_FACTORY = createRegistry(Registries.RESOLUTION_FACTORY); - public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY); - public static final Registry HITBOX_FACTORY = createRegistry(Registries.HITBOX_FACTORY); - public static final Registry RESOURCE_PACK_HOST_FACTORY = createRegistry(Registries.RESOURCE_PACK_HOST_FACTORY); - public static final Registry> EVENT_FUNCTION_FACTORY = createRegistry(Registries.EVENT_FUNCTION_FACTORY); - public static final Registry> EVENT_CONDITION_FACTORY = createRegistry(Registries.EVENT_CONDITION_FACTORY); - public static final Registry> PLAYER_SELECTOR_FACTORY = createRegistry(Registries.PLAYER_SELECTOR_FACTORY); + public static final Registry BLOCK = createDynamicBoundRegistry(Registries.BLOCK); + public static final Registry BLOCK_BEHAVIOR_FACTORY = createConstantBoundRegistry(Registries.BLOCK_BEHAVIOR_FACTORY); + public static final Registry ITEM_BEHAVIOR_FACTORY = createConstantBoundRegistry(Registries.ITEM_BEHAVIOR_FACTORY); + public static final Registry PROPERTY_FACTORY = createConstantBoundRegistry(Registries.PROPERTY_FACTORY); + public static final Registry> LOOT_FUNCTION_FACTORY = createConstantBoundRegistry(Registries.LOOT_FUNCTION_FACTORY); + public static final Registry> LOOT_CONDITION_FACTORY = createConstantBoundRegistry(Registries.LOOT_CONDITION_FACTORY); + public static final Registry> LOOT_ENTRY_CONTAINER_FACTORY = createConstantBoundRegistry(Registries.LOOT_ENTRY_CONTAINER_FACTORY); + public static final Registry NUMBER_PROVIDER_FACTORY = createConstantBoundRegistry(Registries.NUMBER_PROVIDER_FACTORY); + public static final Registry TEMPLATE_ARGUMENT_FACTORY = createConstantBoundRegistry(Registries.TEMPLATE_ARGUMENT_FACTORY); + public static final Registry ITEM_MODEL_FACTORY = createConstantBoundRegistry(Registries.ITEM_MODEL_FACTORY); + public static final Registry ITEM_MODEL_READER = createConstantBoundRegistry(Registries.ITEM_MODEL_READER); + public static final Registry TINT_FACTORY = createConstantBoundRegistry(Registries.TINT_FACTORY); + public static final Registry TINT_READER = createConstantBoundRegistry(Registries.TINT_READER); + public static final Registry SPECIAL_MODEL_FACTORY = createConstantBoundRegistry(Registries.SPECIAL_MODEL_FACTORY); + public static final Registry SPECIAL_MODEL_READER = createConstantBoundRegistry(Registries.SPECIAL_MODEL_READER); + public static final Registry RANGE_DISPATCH_PROPERTY_FACTORY = createConstantBoundRegistry(Registries.RANGE_DISPATCH_PROPERTY_FACTORY); + public static final Registry RANGE_DISPATCH_PROPERTY_READER = createConstantBoundRegistry(Registries.RANGE_DISPATCH_PROPERTY_READER); + public static final Registry CONDITION_PROPERTY_FACTORY = createConstantBoundRegistry(Registries.CONDITION_PROPERTY_FACTORY); + public static final Registry CONDITION_PROPERTY_READER = createConstantBoundRegistry(Registries.CONDITION_PROPERTY_READER); + public static final Registry SELECT_PROPERTY_FACTORY = createConstantBoundRegistry(Registries.SELECT_PROPERTY_FACTORY); + public static final Registry SELECT_PROPERTY_READER = createConstantBoundRegistry(Registries.SELECT_PROPERTY_READER); + public static final Registry> RECIPE_FACTORY = createConstantBoundRegistry(Registries.RECIPE_FACTORY); + public static final Registry FORMULA_FACTORY = createConstantBoundRegistry(Registries.FORMULA_FACTORY); + public static final Registry> PATH_MATCHER_FACTORY = createConstantBoundRegistry(Registries.PATH_MATCHER_FACTORY); + public static final Registry RESOLUTION_FACTORY = createConstantBoundRegistry(Registries.RESOLUTION_FACTORY); + public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createConstantBoundRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY); + public static final Registry HITBOX_FACTORY = createConstantBoundRegistry(Registries.HITBOX_FACTORY); + public static final Registry RESOURCE_PACK_HOST_FACTORY = createConstantBoundRegistry(Registries.RESOURCE_PACK_HOST_FACTORY); + public static final Registry> EVENT_FUNCTION_FACTORY = createConstantBoundRegistry(Registries.EVENT_FUNCTION_FACTORY); + public static final Registry> EVENT_CONDITION_FACTORY = createConstantBoundRegistry(Registries.EVENT_CONDITION_FACTORY); + public static final Registry> PLAYER_SELECTOR_FACTORY = createConstantBoundRegistry(Registries.PLAYER_SELECTOR_FACTORY); + public static final Registry EQUIPMENT_FACTORY = createConstantBoundRegistry(Registries.EQUIPMENT_FACTORY); + public static final Registry SLOT_DISPLAY_TYPE = createConstantBoundRegistry(Registries.SLOT_DISPLAY_TYPE); + public static final Registry RECIPE_DISPLAY_TYPE = createConstantBoundRegistry(Registries.RECIPE_DISPLAY_TYPE); + public static final Registry LEGACY_RECIPE_TYPE = createConstantBoundRegistry(Registries.LEGACY_RECIPE_TYPE); - private static Registry createRegistry(ResourceKey> key) { - return new MappedRegistry<>(key); + private static Registry createConstantBoundRegistry(ResourceKey> key) { + return new ConstantBoundRegistry<>(key); + } + + private static Registry createDynamicBoundRegistry(ResourceKey> key) { + return new DynamicBoundRegistry<>(key); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/ConstantBoundRegistry.java b/core/src/main/java/net/momirealms/craftengine/core/registry/ConstantBoundRegistry.java new file mode 100644 index 000000000..cf3da4675 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/ConstantBoundRegistry.java @@ -0,0 +1,57 @@ +package net.momirealms.craftengine.core.registry; + +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.ResourceKey; + +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Objects; + +public class ConstantBoundRegistry extends AbstractMappedRegistry { + protected final Reference2IntMap toId = MCUtils.make(new Reference2IntOpenHashMap<>(), map -> map.defaultReturnValue(-1)); + protected final Map> byValue = new IdentityHashMap<>(512); + + public ConstantBoundRegistry(ResourceKey> key) { + super(key); + } + + @Override + public Holder.Reference registerForHolder(ResourceKey key) { + throw new IllegalArgumentException("Cannot register a holder for a MappedRegistry"); + } + + @Override + public Holder.Reference register(ResourceKey key, T value) { + Objects.requireNonNull(key); + if (!key.registry().equals(super.key.location())) { + throw new IllegalStateException(key + " is not allowed to be registered in " + this.key); + } + if (this.byResourceLocation.containsKey(key.location())) { + throw new IllegalStateException("Adding duplicate key '" + key + "' to registry"); + } else { + Holder.Reference reference = this.byResourceKey.computeIfAbsent(key, k -> Holder.Reference.createConstant(this, k, value)); + this.byResourceKey.put(key, reference); + this.byResourceLocation.put(key.location(), reference); + int size = this.byId.size(); + this.byId.add(reference); + this.toId.put(value, size); + this.byValue.put(value, reference); + return reference; + } + } + + @Override + public int getId(T value) { + return this.toId.getInt(value); + } + + @Override + public Key getKey(T value) { + Holder.Reference reference = this.byValue.get(value); + if (reference == null) return null; + return reference.key().location(); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/DynamicBoundRegistry.java b/core/src/main/java/net/momirealms/craftengine/core/registry/DynamicBoundRegistry.java new file mode 100644 index 000000000..47808d13f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/DynamicBoundRegistry.java @@ -0,0 +1,48 @@ +package net.momirealms.craftengine.core.registry; + +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceKey; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public class DynamicBoundRegistry extends AbstractMappedRegistry { + + public DynamicBoundRegistry(ResourceKey> key) { + super(key); + } + + @Override + public Holder.Reference registerForHolder(ResourceKey key) { + Objects.requireNonNull(key); + if (!key.registry().equals(this.key.location())) { + throw new IllegalStateException(key + " is not allowed to be registered in " + this.key); + } + if (this.byResourceLocation.containsKey(key.location())) { + throw new IllegalStateException("Adding duplicate key '" + key + "' to registry"); + } else { + Holder.Reference reference = this.byResourceKey.computeIfAbsent(key, k -> Holder.Reference.create(this, k)); + this.byResourceKey.put(key, reference); + this.byResourceLocation.put(key.location(), reference); + this.byId.add(reference); + return reference; + } + } + + @Override + public Holder.Reference register(ResourceKey key, T value) { + Holder.Reference holder = registerForHolder(key); + holder.bindValue(value); + return holder; + } + + @Override + public int getId(@Nullable T value) { + throw new UnsupportedOperationException("getId is not supported for dynamic bound registry"); + } + + @Override + public Key getKey(T value) { + throw new UnsupportedOperationException("getKey is not supported for dynamic bound registry"); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java index d4aae38ea..b1e319931 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Holder.java @@ -118,6 +118,10 @@ public interface Holder { return new Reference<>(owner, registryKey, null); } + public static Reference createConstant(Owner owner, ResourceKey registryKey, T value) { + return new Constant<>(owner, registryKey, value); + } + public ResourceKey key() { if (this.key == null) { throw new IllegalStateException("Trying to access unbound value '" + this.value + "' from registry " + this.owner); @@ -204,6 +208,18 @@ public interface Holder { public String toString() { return "Reference{" + this.key + "=" + this.value + "}"; } + + static class Constant extends Reference { + + public Constant(Owner owner, @Nullable ResourceKey key, @Nullable A value) { + super(owner, key, value); + } + + @Override + public void bindValue(A value) { + throw new UnsupportedOperationException(); + } + } } interface Owner { diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index c050b9642..cbdfba555 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -5,8 +5,12 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.PropertyFactory; import net.momirealms.craftengine.core.entity.furniture.HitBoxFactory; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.equipment.EquipmentFactory; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.RecipeFactory; +import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipe; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplay; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.loot.entry.LootEntryContainerFactory; import net.momirealms.craftengine.core.loot.function.ApplyBonusCountFunction; @@ -37,36 +41,40 @@ import net.momirealms.craftengine.core.util.ResourceKey; public class Registries { public static final Key ROOT_REGISTRY = Key.withDefaultNamespace("root"); - public static final ResourceKey> BLOCK = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("block")); - public static final ResourceKey> OPTIMIZED_ITEM_ID = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("optimized_item_id")); - public static final ResourceKey> PROPERTY_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("property_factory")); - public static final ResourceKey> BLOCK_BEHAVIOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("block_behavior_factory")); - public static final ResourceKey> ITEM_BEHAVIOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("item_behavior_factory")); - public static final ResourceKey>> LOOT_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("loot_function_factory")); - public static final ResourceKey>> LOOT_ENTRY_CONTAINER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("loot_entry_container_factory")); - public static final ResourceKey>> LOOT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("loot_condition_factory")); - public static final ResourceKey> NUMBER_PROVIDER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("number_provider_factory")); - public static final ResourceKey> TEMPLATE_ARGUMENT_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("template_argument_factory")); - public static final ResourceKey> ITEM_MODEL_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("item_model_factory")); - public static final ResourceKey> ITEM_MODEL_READER = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("item_model_reader")); - public static final ResourceKey> TINT_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("tint_factory")); - public static final ResourceKey> TINT_READER = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("tint_reader")); - public static final ResourceKey> SPECIAL_MODEL_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("special_model_factory")); - public static final ResourceKey> SPECIAL_MODEL_READER = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("special_model_reader")); - public static final ResourceKey> RANGE_DISPATCH_PROPERTY_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("range_dispatch_property_factory")); - public static final ResourceKey> RANGE_DISPATCH_PROPERTY_READER = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("range_dispatch_property_reader")); - public static final ResourceKey> CONDITION_PROPERTY_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("condition_property_factory")); - public static final ResourceKey> CONDITION_PROPERTY_READER = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("condition_property_reader")); - public static final ResourceKey> SELECT_PROPERTY_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("select_property_factory")); - public static final ResourceKey> SELECT_PROPERTY_READER = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("select_property_reader")); - public static final ResourceKey>> RECIPE_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_factory")); - public static final ResourceKey> FORMULA_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("formula_factory")); - public static final ResourceKey>> PATH_MATCHER_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory")); - public static final ResourceKey> RESOLUTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resolution_factory")); - public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); - public static final ResourceKey> HITBOX_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); - public static final ResourceKey> RESOURCE_PACK_HOST_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory")); - public static final ResourceKey>> EVENT_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("event_function_factory")); - public static final ResourceKey>> EVENT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("event_condition_factory")); - public static final ResourceKey>> PLAYER_SELECTOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_selector")); + public static final ResourceKey> BLOCK = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("block")); + public static final ResourceKey> OPTIMIZED_ITEM_ID = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("optimized_item_id")); + public static final ResourceKey> PROPERTY_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("property_factory")); + public static final ResourceKey> BLOCK_BEHAVIOR_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("block_behavior_factory")); + public static final ResourceKey> ITEM_BEHAVIOR_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("item_behavior_factory")); + public static final ResourceKey>> LOOT_FUNCTION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("loot_function_factory")); + public static final ResourceKey>> LOOT_ENTRY_CONTAINER_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("loot_entry_container_factory")); + public static final ResourceKey>> LOOT_CONDITION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("loot_condition_factory")); + public static final ResourceKey> NUMBER_PROVIDER_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("number_provider_factory")); + public static final ResourceKey> TEMPLATE_ARGUMENT_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("template_argument_factory")); + public static final ResourceKey> ITEM_MODEL_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("item_model_factory")); + public static final ResourceKey> ITEM_MODEL_READER = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("item_model_reader")); + public static final ResourceKey> TINT_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("tint_factory")); + public static final ResourceKey> TINT_READER = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("tint_reader")); + public static final ResourceKey> SPECIAL_MODEL_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("special_model_factory")); + public static final ResourceKey> SPECIAL_MODEL_READER = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("special_model_reader")); + public static final ResourceKey> RANGE_DISPATCH_PROPERTY_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("range_dispatch_property_factory")); + public static final ResourceKey> RANGE_DISPATCH_PROPERTY_READER = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("range_dispatch_property_reader")); + public static final ResourceKey> CONDITION_PROPERTY_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("condition_property_factory")); + public static final ResourceKey> CONDITION_PROPERTY_READER = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("condition_property_reader")); + public static final ResourceKey> SELECT_PROPERTY_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("select_property_factory")); + public static final ResourceKey> SELECT_PROPERTY_READER = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("select_property_reader")); + public static final ResourceKey>> RECIPE_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_factory")); + public static final ResourceKey> FORMULA_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("formula_factory")); + public static final ResourceKey>> PATH_MATCHER_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("path_matcher_factory")); + public static final ResourceKey> RESOLUTION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("resolution_factory")); + public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); + public static final ResourceKey> HITBOX_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); + public static final ResourceKey> RESOURCE_PACK_HOST_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory")); + public static final ResourceKey>> EVENT_FUNCTION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("event_function_factory")); + public static final ResourceKey>> EVENT_CONDITION_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("event_condition_factory")); + public static final ResourceKey>> PLAYER_SELECTOR_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("player_selector_factory")); + public static final ResourceKey> EQUIPMENT_FACTORY = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("equipment_factory")); + public static final ResourceKey> SLOT_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("slot_display_type")); + public static final ResourceKey> RECIPE_DISPLAY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("recipe_display_type")); + public static final ResourceKey> LEGACY_RECIPE_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("legacy_recipe_type")); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registry.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registry.java index 970d47b15..ef9a3438a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registry.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registry.java @@ -18,6 +18,13 @@ public interface Registry extends Holder.Owner { @Nullable T getValue(@Nullable Key id); + @Nullable + T getValue(int id); + + int getId(T value); + + Key getKey(T value); + Set keySet(); Set, T>> entrySet(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/WritableRegistry.java b/core/src/main/java/net/momirealms/craftengine/core/registry/WritableRegistry.java index bd485a885..a618f02c7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/WritableRegistry.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/WritableRegistry.java @@ -6,6 +6,10 @@ public interface WritableRegistry extends Registry { Holder.Reference registerForHolder(ResourceKey key); + default Holder.Reference getOrRegisterForHolder(ResourceKey key) { + return this.get(key).orElseGet(() -> registerForHolder(key)); + } + Holder.Reference register(ResourceKey key, T value); boolean isEmpty(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java index dd6e52699..eaa7df2ba 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java @@ -40,6 +40,7 @@ public abstract class AbstractSoundManager implements SoundManager { public void unload() { this.byId.clear(); this.byNamespace.clear(); + this.songs.clear(); } @Override @@ -60,7 +61,7 @@ public abstract class AbstractSoundManager implements SoundManager { protected abstract void registerSongs(Map songs); public class SongParser implements ConfigParser { - public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "song", "songs", "jukebox", "jukebox_song"}; + public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "jukebox_song", "jukebox-songs", "jukebox-song"}; @Override public int loadingSequence() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java b/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java index 3d9baffca..68e30c8a2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.util; import com.google.common.collect.Maps; +import com.mojang.datafixers.util.Either; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufInputStream; @@ -10,6 +11,8 @@ import io.netty.handler.codec.EncoderException; import io.netty.util.ByteProcessor; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.registry.Registry; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.sparrow.nbt.NBT; import net.momirealms.sparrow.nbt.Tag; @@ -19,6 +22,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.FileChannel; @@ -26,6 +30,7 @@ import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.*; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -44,30 +49,80 @@ public class FriendlyByteBuf extends ByteBuf { return source; } + public Component readComponent() { + if (VersionHelper.isOrAbove1_20_3()) { + return AdventureHelper.nbtToComponent(this.readNbt(false)); + } else { + return AdventureHelper.jsonToComponent(this.readUtf()); + } + } + + public void writeComponent(Component component) { + if (VersionHelper.isOrAbove1_20_3()) { + this.writeNbt(AdventureHelper.componentToNbt(component), false); + } else { + this.writeUtf(AdventureHelper.componentToJson(component)); + } + } + + public Instant readInstant() { + return Instant.ofEpochMilli(this.readLong()); + } + + public void writeInstant(Instant instant) { + this.writeLong(instant.toEpochMilli()); + } + public > C readCollection(IntFunction collectionFactory, Reader reader) { int i = this.readVarInt(); - C c0 = (C)(collectionFactory.apply(i)); - + C collection = collectionFactory.apply(i); for(int j = 0; j < i; ++j) { - c0.add(reader.apply(this)); + collection.add(reader.apply(this)); } - - return c0; + return collection; } public void writeCollection(Collection collection, Writer writer) { this.writeVarInt(collection.size()); - - for(T t0 : collection) { - writer.accept(this, t0); + for (T t : collection) { + writer.accept(this, t); } + } + @SuppressWarnings("unchecked") + public T[] readArray(Reader reader, Class type) { + int i = this.readVarInt(); + T[] array = (T[]) Array.newInstance(type, i); + for(int j = 0; j < i; ++j) { + array[j] = reader.apply(this); + } + return array; + } + + public void writeArray(T[] array, Writer writer) { + this.writeVarInt(array.length); + for(T t : array) { + writer.accept(this, t); + } } public BlockPos readBlockPos() { return BlockPos.of(this.readLong()); } + public OptionalInt readOptionalVarInt() { + int i = this.readVarInt(); + return i == 0 ? OptionalInt.empty() : OptionalInt.of(i - 1); + } + + public void writeOptionalVarInt(OptionalInt optionalInt) { + if (optionalInt.isPresent()) { + this.writeVarInt(optionalInt.getAsInt() + 1); + } else { + this.writeVarInt(0); + } + } + public int readContainerId() { return VersionHelper.isOrAbove1_21_2() ? this.readVarInt() : this.readUnsignedByte(); } @@ -331,6 +386,15 @@ public class FriendlyByteBuf extends ByteBuf { return byteArray; } + public T readById(Registry registry) { + int id = this.readVarInt(); + return registry.getValue(id); + } + + public void writeById(Registry registry, T value) { + this.writeVarInt(registry.getId(value)); + } + public int readVarInt() { int value = 0; int shift = 0; @@ -378,6 +442,49 @@ public class FriendlyByteBuf extends ByteBuf { return this; } + public Either readHolder(Reader reader) { + int id = this.readVarInt(); + if (id == 0) { + return Either.right(reader.apply(this)); + } else { + return Either.left(id - 1); + } + } + + public void writeHolder(Either holder, Writer writer) { + holder.ifLeft(i -> writeVarInt(i + 1)).ifRight(t -> { + writeVarInt(0); + writer.accept(this, t); + }); + } + + public Either, Key> readHolderSet() { + int id = this.readVarInt(); + if (id == 0) { + return Either.right(readKey()); + } else { + List list = new ArrayList<>(); + for (int i = 0; i < id - 1; ++i) { + list.add(readVarInt()); + } + return Either.left(list); + } + } + + public void writeHolderSet(Either, Key> holderSet) { + holderSet.ifLeft( + ints -> { + writeVarInt(ints.size() + 1); + for (Integer anInt : ints) { + writeVarInt(anInt); + } + } + ).ifRight(key -> { + writeVarInt(0); + writeKey(key); + }); + } + public FriendlyByteBuf writeVarLong(long value) { while ((value & -128L) != 0L) { this.writeByte((int) (value & 127L) | 128); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ItemUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ItemUtils.java new file mode 100644 index 000000000..10ef0be4e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ItemUtils.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.core.util; + +import net.momirealms.craftengine.core.item.Item; + +public final class ItemUtils { + private ItemUtils() { + } + + public static boolean isEmpty(Item item) { + return item == null || item.isEmpty(); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/LazyReference.java b/core/src/main/java/net/momirealms/craftengine/core/util/LazyReference.java new file mode 100644 index 000000000..1a1fcfe89 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/LazyReference.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.core.util; + +import java.util.function.Supplier; + +public interface LazyReference { + + T get(); + + static LazyReference lazyReference(final Supplier supplier) { + return new LazyReference<>() { + private T value; + + @Override + public T get() { + if (this.value == null) { + this.value = supplier.get(); + } + return this.value; + } + }; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MinecraftVersion.java b/core/src/main/java/net/momirealms/craftengine/core/util/MinecraftVersion.java index 5aae1211c..75c383dd7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MinecraftVersion.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MinecraftVersion.java @@ -20,6 +20,7 @@ public final class MinecraftVersion implements Comparable { PACK_FORMATS.put(1_21_04, 46); PACK_FORMATS.put(1_21_05, 55); PACK_FORMATS.put(1_21_06, 63); + PACK_FORMATS.put(1_21_07, 64); // TODO 1.21.7-rc2 PACK_FORMATS.put(1_99_99, 1000); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MinecraftVersions.java b/core/src/main/java/net/momirealms/craftengine/core/util/MinecraftVersions.java index dd66400dc..a368a809a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MinecraftVersions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MinecraftVersions.java @@ -17,5 +17,6 @@ public final class MinecraftVersions { public static final MinecraftVersion V1_21_4 = new MinecraftVersion("1.21.4"); public static final MinecraftVersion V1_21_5 = new MinecraftVersion("1.21.5"); public static final MinecraftVersion V1_21_6 = new MinecraftVersion("1.21.6"); + public static final MinecraftVersion V1_21_7 = new MinecraftVersion("1.21.7"); public static final MinecraftVersion FUTURE = new MinecraftVersion("1.99.99"); } 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 ee228fab9..f3b1bf95c 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 @@ -7,6 +7,7 @@ import org.joml.Vector3f; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; public class MiscUtils { @@ -130,4 +131,12 @@ public class MiscUtils { } } } + + public static T requireNonNullIf(T o, boolean condition) { + if (condition) { + return Objects.requireNonNull(o); + } else { + return o; + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceKey.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceKey.java index b8b65ed97..6e1ed0ded 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceKey.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceKey.java @@ -1,16 +1,22 @@ package net.momirealms.craftengine.core.util; +import com.google.common.collect.MapMaker; + +import java.util.Map; + public class ResourceKey { + private static final Map> VALUES = (new MapMaker()).weakValues().makeMap(); private final Key registry; private final Key location; - public ResourceKey(Key registry, Key location) { + private ResourceKey(Key registry, Key location) { this.registry = registry; this.location = location; } + @SuppressWarnings("unchecked") public static ResourceKey create(Key registry, Key location) { - return new ResourceKey<>(registry, location); + return (ResourceKey) VALUES.computeIfAbsent(new Internal(registry, location), (key) -> new ResourceKey<>(key.registry, key.location)); } public Key registry() { @@ -25,4 +31,7 @@ public class ResourceKey { public String toString() { return "ResourceKey[" + this.registry + " / " + this.location + "]"; } + + record Internal(Key registry, Key location) { + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Tristate.java b/core/src/main/java/net/momirealms/craftengine/core/util/Tristate.java index 1e3487202..3a37fe8cf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Tristate.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Tristate.java @@ -24,4 +24,12 @@ public enum Tristate { public boolean asBoolean() { return this.booleanValue; } + + public boolean asBoolean(boolean defaultValue) { + if (this == UNDEFINED) { + return defaultValue; + } else { + return this.booleanValue; + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/UUIDUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/UUIDUtils.java index 9d29dc019..40a812d7c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/UUIDUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/UUIDUtils.java @@ -6,4 +6,18 @@ public final class UUIDUtils { public static final UUID EMPTY = new UUID(0, 0); private UUIDUtils() {} + + public static UUID uuidFromIntArray(int[] array) { + return new UUID((long) array[0] << 32 | (long) array[1] & 4294967295L, (long) array[2] << 32 | (long) array[3] & 4294967295L); + } + + public static int[] uuidToIntArray(UUID uuid) { + long l = uuid.getMostSignificantBits(); + long m = uuid.getLeastSignificantBits(); + return leastMostToIntArray(l, m); + } + + private static int[] leastMostToIntArray(long uuidMost, long uuidLeast) { + return new int[]{(int) (uuidMost >> 32), (int) uuidMost, (int) (uuidLeast >> 32), (int) uuidLeast}; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/UniqueKey.java b/core/src/main/java/net/momirealms/craftengine/core/util/UniqueKey.java new file mode 100644 index 000000000..1a4591535 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/UniqueKey.java @@ -0,0 +1,36 @@ +package net.momirealms.craftengine.core.util; + +import net.momirealms.craftengine.core.item.ItemKeys; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public final class UniqueKey { + private static final Map CACHE = new HashMap<>(4096, 0.5f); + public static final UniqueKey AIR = UniqueKey.create(ItemKeys.AIR); + + private final Key key; + + private UniqueKey(Key key) { + this.key = key; + } + + public static UniqueKey create(Key key) { + return CACHE.computeIfAbsent(key, UniqueKey::new); + } + + @Nullable + public static UniqueKey getCached(Key key) { + return CACHE.get(key); + } + + public Key key() { + return this.key; + } + + @Override + public String toString() { + return this.key.toString(); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java index 4fceb5606..f88a0f19d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java @@ -29,6 +29,7 @@ public class VersionHelper { private static final boolean v1_21_4; private static final boolean v1_21_5; private static final boolean v1_21_6; + private static final boolean v1_21_7; static { try (InputStream inputStream = Class.forName("net.minecraft.obfuscate.DontObfuscate").getResourceAsStream("/version.json")) { @@ -36,7 +37,7 @@ public class VersionHelper { throw new IOException("Failed to load version.json"); } JsonObject json = GsonHelper.parseJsonToJsonObject(new String(inputStream.readAllBytes(), StandardCharsets.UTF_8)); - String versionString = json.getAsJsonPrimitive("id").getAsString(); + String versionString = json.getAsJsonPrimitive("id").getAsString().split("-", 2)[0]; MINECRAFT_VERSION = new MinecraftVersion(versionString); @@ -44,8 +45,8 @@ public class VersionHelper { int major = Integer.parseInt(split[1]); int minor = split.length == 3 ? Integer.parseInt(split[2].split("-", 2)[0]) : 0; - // 2001 = 1.20.1 - // 2104 = 1.21.4 + // 12001 = 1.20.1 + // 12104 = 1.21.4 version = parseVersionToInteger(versionString); v1_20 = version >= 12000; @@ -62,6 +63,7 @@ public class VersionHelper { v1_21_4 = version >= 12104; v1_21_5 = version >= 12105; v1_21_6 = version >= 12106; + v1_21_7 = version >= 12107; majorVersion = major; minorVersion = minor; @@ -209,4 +211,8 @@ public class VersionHelper { public static boolean isOrAbove1_21_6() { return v1_21_6; } + + public static boolean isOrAbove1_21_7() { + return v1_21_7; + } } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java index 9e6b41426..f95c1bde6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultSectionSerializer.java @@ -61,7 +61,7 @@ public final class DefaultSectionSerializer { Key key = Key.of(id); Holder owner = BuiltInRegistries.BLOCK.get(key).orElseGet(() -> { Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder( - new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), key)); + ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), key)); InactiveCustomBlock inactiveBlock = new InactiveCustomBlock(key, holder); holder.bindValue(inactiveBlock); return holder; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java index 3f3ae7a3c..be5c7af95 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/BlockStateData.java @@ -1,16 +1,16 @@ package net.momirealms.craftengine.core.world.particle; import net.momirealms.craftengine.core.block.BlockStateWrapper; -import net.momirealms.craftengine.core.block.LazyBlockState; +import net.momirealms.craftengine.core.util.LazyReference; public class BlockStateData implements ParticleData { - private final LazyBlockState blockState; + private final LazyReference blockState; - public BlockStateData(LazyBlockState blockState) { + public BlockStateData(LazyReference blockState) { this.blockState = blockState; } public BlockStateWrapper blockState() { - return blockState.getState(); + return blockState.get(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java index 17eaa1fb9..a9b66f490 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/particle/ItemStackData.java @@ -1,16 +1,16 @@ package net.momirealms.craftengine.core.world.particle; -import net.momirealms.craftengine.core.item.DelayedInitItem; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.util.LazyReference; public class ItemStackData implements ParticleData { - private final DelayedInitItem item; + private final LazyReference> item; - public ItemStackData(DelayedInitItem item) { + public ItemStackData(LazyReference> item) { this.item = item; } public Item item() { - return item.getItem(); + return item.get(); } } diff --git a/gradle.properties b/gradle.properties index f29b46424..fd689d2ad 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,17 +2,17 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.59 -config_version=40 -lang_version=21 +project_version=0.0.60 +config_version=41 +lang_version=22 project_group=net.momirealms -latest_supported_version=1.21.6 +latest_supported_version=1.21.7 # Supported languages -supported_languages=en,zh_cn,zh_tw,es,tr,de +supported_languages=en,zh_cn,zh_tw,es,tr,de,ru_ru # Dependency settings -paper_version=1.21.6 +paper_version=1.21.7 jetbrains_annotations_version=26.0.2 slf4j_version=2.0.17 log4j_version=2.24.3 @@ -23,10 +23,10 @@ jar_relocator_version=1.7 adventure_bundle_version=4.23.0 cloud_core_version=2.0.0 cloud_services_version=2.0.0 -cloud_brigadier_version=2.0.0-beta.10 -cloud_bukkit_version=2.0.0-beta.10 -cloud_paper_version=2.0.0-beta.10 -cloud_minecraft_extras_version=2.0.0-beta.10 +cloud_brigadier_version=2.0.0-beta.11 +cloud_bukkit_version=2.0.0-beta.11 +cloud_paper_version=2.0.0-beta.11 +cloud_minecraft_extras_version=2.0.0-beta.11 boosted_yaml_version=1.3.7 bstats_version=3.1.0 caffeine_version=3.2.0 @@ -39,7 +39,7 @@ 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.1 +sparrow_nbt_version=0.9.4 sparrow_util_version=0.50.6 fastutil_version=8.5.15 netty_version=4.1.121.Final @@ -49,13 +49,14 @@ mojang_brigadier_version=1.0.18 byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.4 -anti_grief_version=0.17 -nms_helper_version=1.0.18 +anti_grief_version=0.18 +nms_helper_version=1.0.34 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.31.23 amazon_awssdk_eventstream_version=1.0.1 jimfs_version=1.3.0 +authlib_version=6.0.58 # Proxy settings #systemProp.socks.proxyHost=127.0.0.1